home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / keyb / alias450.zip / ALIAS.ASM next >
Assembly Source File  |  1990-02-04  |  236KB  |  6,113 lines

  1.  
  2. Title   ALIAS.COM   Command line editor/abbreviator for MS-DOS
  3. comment |           ; start of comment block
  4.  
  5.                                                                        
  6.           A       L           I I I I I         A          S S S
  7.         A   A     L               I           A   A      S       S
  8.       A       A   L               I         A       A    S
  9.       A       A   L               I         A       A      S S S
  10.       A A A A A   L               I         A A A A A            S
  11.       A       A   L               I         A       A    S       S
  12.       A       A   L L L L L   I I I I I     A       A      S S S
  13.  
  14.  
  15.  -----------------------------------------------------------------------
  16.                             F U N C T I O N
  17.  -----------------------------------------------------------------------
  18.  
  19. This program adds a number of resident commands to DOS to implement a
  20. form of the Alias command as found on other computers.  See the variables
  21. area under 'help_text' for a list of the facilities provided, or install
  22. it by typing ALIAS at the DOS prompt, and then view the help screen by
  23. typing ALIAS ? at the prompt.
  24.  
  25. Like aliases, DOS commands typed at the prompt can be split with
  26. the & character, as long as aliases are turned on (type ALIAS ? at the
  27. prompt, for help).
  28.  
  29. ALIAS also incorporates a DOSEDIT-like facility, so ALIAS is a full
  30. superset of DOSEDIT, CED and the like.
  31.  
  32. Also, command completion is offered.  Type the first few characters of a
  33. command and press the prf_trigger key.  If a matching command is found, it
  34. will be put on screen to complete the part-typed command.  See the code
  35. for the definition of the prf_trigger key.  Why prf?  Well, during development
  36. it was known as parameter recall facility.
  37.  
  38. This file (ALIAS.ASM) comprises the entire source code.  No other files
  39. are needed to create ALIAS.COM.  The help text is a plain ASCII file called
  40. ALIAS.HLP.
  41.  
  42. Note that this resident program uses the default MS-DOS stack and does not
  43. create its own.  This has not caused any known problems.  (The DOSEDIT code
  44. sets up its own stack, but the rest of ALIAS does not use it, yet).
  45.  
  46.  
  47.   -----------------------------------------------------------------------
  48.                       I M P O R T A N T    N O T E S
  49.   -----------------------------------------------------------------------
  50.  
  51. 1.  This source code is made available for personal use only.  You can
  52.     learn from it, steal my routines, and make your own custom 
  53.     versions of the program.
  54.  
  55.     YOU MUST NOT make your own customised or enhanced versions generally
  56.     available on any BBS or by any other means.
  57.  
  58.     The only way to incorporate your enhancements into the distribution
  59.     version of ALIAS is to send ideas or code fragments (not whole new copies
  60.     of this file, please!) to the author.
  61.  
  62. 2.  If you start changing the code in here, some things may not work properly.
  63.     Just because the table size is defined as an equate, this does not mean
  64.     that you can necessarily enlarge the table by simply changing the equate.
  65.     If you change the code, and your machine crashes, that's not my fault.
  66.  
  67. 3.  There are two conditional assembly instructions in the code.  If DEBUG is
  68.     set, a number of debug procedures wil be assembled but not called. They
  69.     can be called by inserting CALL commands as required.  If ONLINE_HELP is
  70.     set, the online help will be available, as documented, with the ALIAS ?
  71.     command.  If ONLINE_HELP is not set, the online help is not assembled, and
  72.     is replaced with a short message to this effect.  This saves around 2K of
  73.     RAM when ALIAS is loaded, but means that users will have to read the
  74.     ALIAS.HLP documentation file to get help.
  75.  
  76.   -----------------------------------------------------------------------
  77.    B U G   F I X E S   A N D   A M E N D M E N T S   T O   B E   D O N E
  78.   -----------------------------------------------------------------------
  79.  
  80. Add DOS compatibility with function keys for Psion.  To do by mid Jan 1990.
  81.  
  82. Should PgUp and PgDn redraw the display line?
  83.  
  84. Trap func 29h, which the batch file interpreter uses to parse strings.  Copy
  85. commands retrieved from batch files, into the ALIAS history buffer.
  86.  
  87. Add an ALIAS E command to edit an alias, or do separate ALIAS2WP and WP2ALIAS
  88. file conversion programs.  If programs, make one prog.  Use Basic 7?
  89.  
  90. ALIAS D has the colour bug if used on the bottom line.
  91.  
  92. Add an extended keyboard buffer to 128 bytes.  This may be difficult, as DOS 4
  93. is too large to keep the buffer within segment 40h.
  94.  
  95. Add executable filenames?  eg  ALIAS A *.ASM PE *.ASM, ie the asterisk
  96. stands for the primary filename in both sides of the alias definition.
  97. The code for ALIAS A already permits this, so it's just the expander that
  98. needs expanding!
  99.  
  100. Ignore separator characters unless surrounded by spaces, else the user can't
  101. have filenames with ampersands in.
  102.  
  103. The colour bug is still in ALIAS S.
  104.  
  105.  There's a problem when PC-Tools is loaded resident.
  106.  
  107.  There's a problem with Borland's Sprint.  See message on Cix for more.
  108.  
  109.  Multiple-command lines can't have nested aliases.  Eg, if you
  110.  have ALIAS A CD CHDIR then CD FRED & DIR will use CD and not CHDIR
  111.  to change directories.  Demon@Cix found this bug, so mail him when
  112.  it's fixed.  Reported in exe/files #250 on Cix.
  113.  
  114.  There are problems with Sidekick Plus.  See message on Cix.
  115.  
  116.  If SHOW mode is on and user types 11&22, the 22 gets echoed twice.  It seems
  117.  that echo proc is being called from both 'call echo' statements.
  118.  
  119.   -----------------------------------------------------------------------
  120.              D E V E L O P M E N T   E N V I R O N M E N T
  121.   -----------------------------------------------------------------------
  122.  
  123.                 Machine:  CompuAdd 386/20 & other PC clones
  124.        Operating System:  MS-DOS 4.01.  Will run under DOS 2, 3 or 4 or 10.
  125.                Language:  8086 assembly language
  126.               Assembler:  SLR Systems OPTASM version 1.5.
  127.                  Linker:  Microsoft Linker version 5.01.20
  128.          Program Format:  Must be run as a .COM file, not .EXE
  129.  Editor for source file:  Word Perfect Program Editor version 4.21.
  130.  
  131.   -----------------------------------------------------------------------
  132.              C R E A T I N G   E X E C U T A B L E   F I L E
  133.   -----------------------------------------------------------------------
  134.  
  135. ALIAS is designed to run as a .COM file and MUST do so.  Strange things will
  136. happen if you make this into an .EXE file, because ALIAS.COM uses parts of
  137. its PSP as buffer space, and does other things which make assumptions about
  138. segments and their position in memory.
  139.  
  140. To create ALIAS.COM:
  141.  
  142. 1.  MASM ALIAS; <---- note the semi colon
  143. 2.  LINK ALIAS; <---- and this one, too
  144. 3.  EXE2BIN ALIAS
  145. 4.  RENAME ALIAS.BIN ALIAS.COM
  146. 5.  DELETE ALIAS.EXE
  147. 6.  DELETE ALIAS.OBJ
  148.  
  149.   -----------------------------------------------------------------------
  150.                  S T R U C T U R E   O F   D A T A
  151.   -----------------------------------------------------------------------
  152.  
  153. The alias table consists of a contiguous block of bytes, each initialized
  154. to zero. Each entry in the table consists of a left hand side and a right
  155. hand side.  The length of the left hand side and right hand side, as well as
  156. the number of entries, are fixed by the equates LHS_LEN, RHS_LEN and TBL_LEN
  157. respectively.  These can be changed prior to reassembling this program,
  158. resulting in an ALIAS.COM of any desired length.  The table is a fixed-length
  159. structure, which is probably not the best way to have written it.
  160.  
  161. After the right hand side part of a table entry comes a zero to signify the
  162. end of an entry.  This extra byte is not included in the count of characters
  163. defined in the equates.
  164.  
  165. If a table entry is empty, the first byte is 0.  If the entry is full, the
  166. first byte is non-zero, there is a string on the right and left side, and ALL
  167. unused bytes in the entry are 0.
  168.  
  169. There are 5 bytes before the actual table data.  These are saved along with
  170. the data, but are not flushed by the ALIAS F command.  These 5 bytes are:
  171.  
  172.           1:         - ins_mode. 0 = overwrite, 1 = insert.
  173.           2:         - status. 0 = abbrevs turned off, 1 = on
  174.           3:         - expand_from.  If 1, global, 0 = DOS prompt only
  175.           4:         - screen colour.  
  176.           5:         - echo_status. Shows whether Show or Hide mode set.
  177.  
  178. There is no identifying string to show that the file is an ALIAS file, or
  179. to specify the lhs and rhs lengths.
  180.  
  181. These flags will need bitmapping if any more data is required to be saved.
  182.  
  183. -------------------------------------------------------------------------
  184.             H I S T O R Y   O F   T H I S   V E R S I O N
  185. -------------------------------------------------------------------------
  186.  
  187. 4.50  Started adding touches of DOS compatibility to the line editor.
  188.       INS and Del work vaguely like DOS!
  189.  
  190. 4.30  Changed function keys around.  Command completion now F8.
  191.       'It' and 'Also' are F9 and F10 respectively.  This leaves F1 to F5
  192.       free, to add full DOS function key compatibility at a later stage.
  193.  
  194. 4.27  Removed help_flag (originally added in v4.12) and added function key
  195.       line to help text.
  196.  
  197.       Changed literal arrow characters in help text to decimal numbers, cos
  198.       the Ctrl-X was screwing up printer listings of the source code.
  199.  
  200. 4.26  Increased length of command completion buffer from 1000 to 1500 chars.
  201.       This value is held in CmdLen.
  202.  
  203. 4.25  ZAP_MSG shortened to save memory. Also, error_msg and disk_msg, and
  204.       version.
  205.  
  206.       Added an online_help conditional assembly switch.  When true, the help
  207.       text is assembled.  Otherwise, no online help is assembled, saving RAM.
  208.  
  209.       UK registration price increased from £20 to £25.
  210.  
  211.       Made parameter recall (the F4 key) case-insensitive, by forcing chars
  212.       to lower case before comparing them in prf_compare.
  213.  
  214.       Made putc routine use DOS rather than the BIOS version that was in NDE.
  215.  
  216.       Rewrote the sign-on text.
  217.  
  218.       Amended some calls to bios_video, so they preserve more registers in
  219.       order to conform to what the IBM tech ref says about int 10h's use
  220.       and corruption of registers.  Should always preserve ax,bp,si and di.
  221.  
  222. 4.24  Greeting message is now printed by a DOS call, rather than using our
  223.       home-made bios version.  The whole greet message can consequently be
  224.       redirected to NUL if it is not required.
  225.  
  226.       Dialcom reference removed from greeting, cos I'm not on Dialcom any more.
  227.  
  228. 4.23  Fixed printregs cos it used to corrupt bp and si.
  229.  
  230. 4.22  Added check to see if user just types a single ampersand as a string.
  231.       If so, kill the string, or ALIAS goes into a loop.
  232.  
  233.       Removed all traces of par_flag.  This was a flag that used to be set
  234.       if the string typed at the prompt was found in the alias table.  If it
  235.       was set, then replace_params (no longer used) would put back the params
  236.       typed after the first word.  Also, echo proc used par_flag, to only echo
  237.       in certain cases.  Now, if show mode is on, we always echo, whether the
  238.       string came from DOS prompt, was part of a multiple line etc.
  239.  
  240. 4.21  Re-implemented filter proc, to filter out LF characters.  Sometimes,
  241.       strings end with CRLF, and bufkey stops with CR so there will be stray
  242.       LF characters around.
  243.  
  244.       Expanded sign-on message.
  245.  
  246.       Uploaded as ALIAS421.COM and .HLP to Bix, 30/4/89.
  247.  
  248. 4.20  Started adding support for % replacable parameters.  After calling
  249.       SUBST, call expand_percents to substitue the percent parameters into
  250.       the ds:dx bufer.
  251.  
  252.       BIOS_BLIP, which makes a beep by using hardware programming and no
  253.       bios calls, renamed to hw_blip.
  254.  
  255.       Released on Cix 3am, 23/4/89.
  256.  
  257. 4.18  Removed no_dollar flag.  Display routines now stop on ascii zero,
  258.       and never on a dollar sign.  This allows aliases to contain dollar
  259.       signs and to be listed properly.
  260.  
  261.       Added F1proc, that does nothing when F1 is pressed. There is no
  262.       need for an F1 key when you have the editing facilities of ALIAS.
  263.  
  264. 4.17  Finally fixed the multiple-size cursor for CGA, EGA, VGA etc.
  265.       Works OK now.
  266.  
  267. 4.16  Experimental bug-fix for cursor size on non-CGA machines.  Need to
  268.       set bit 0 of 0:487?
  269.  
  270. 4.15  Cursor size now indicates insert/overwrite mode.
  271.  
  272. 4.14  Moved insert mode status byte so it gets saved in the data file.
  273.  
  274.       Disabled the filter proc, which prevented control characters being
  275.       typed.  Added F6 key recognition to getc, to make it Ctrl-Z.
  276.  
  277.       If user doesn't type a space before pressing the IT key, a space
  278.       is automatically added to user's string.
  279.  
  280.       Added ESC key to help text.
  281.  
  282.       Added PgUp/Dn commands, and included them in the help text.
  283.  
  284.       Bufkey routine now preserves si, which Norton's version doesn't do.
  285.       ALIAS (and NDE) now work properly with MASM.
  286.  
  287.       ALIAS414.COM released on Cix, 11 Feb 1989.
  288.  
  289. 4.12  Removed token parsing from disp_str_colour, cos the help text was
  290.       getting very confusing.  It is now printed literally.
  291.       Rewrote help text to include more information.  There are no features
  292.       that do not now appear in the help text.
  293.  
  294.       Added help_flag.  It is set before the help text is displayed, and
  295.       cleared again afterwards.  Disp_str_colour puts a white space in column
  296.       1 when the flag is set.  The help text is shifted right by 1 char.
  297.       This means that we can use all 25 lines, without getting the colour
  298.       problem, but only 79 of the 80 columns can be used.  Oh well.
  299.  
  300.       Added line to de-install message to say that user's command buffer
  301.       has been cleared.
  302.  
  303.       Added f3proc, which is called when F3 is pressed.  This is a non-
  304.       destructive version of cursup, which won't overwrite chars to the
  305.       left of the cursor.  This is the way that DOS works normally, compared
  306.       to the destructive cursup proc that used to be called when F3 pressed.
  307.       There is unused code that used to handle F3 before prf and DOSEDIT was
  308.       added.  This has not yet been removed.
  309.  
  310.       Added shareware message, requesting money, to signon screen.
  311.  
  312.       Added F8 key, which is like F4 but doesn't check to make sure that
  313.       the parameters match.  It just retrieves all but the first word of
  314.       the previous command and takes it on to the word that you have typed.
  315.       F8 is known as the IT key, cos you can TYPE a file and then DEL IT,
  316.       rather than specifying its name again.
  317.  
  318.       Added no_dollar flag.  Normally set to 1, which means that
  319.       disp_str_colour will terminate on a dollar sign.  Temporarily set
  320.       to 0 before displaying the greet message, so that we can have a dollar
  321.       character in the sign-on text.
  322.  
  323.       Rewrote help text yet again!  disp_str_proc still puts a white space
  324.       at the start of each line of the help text, so that the text could
  325.       fill the whole screen without corrupting colours.  At present, though,
  326.       the help text only fills about 18 lines.
  327.  
  328.       Removed ALIAS X and ALIAS Y commands, which used to turn prf on and
  329.       off.  No longer needed, now prf trigger is not the space bar.  People
  330.       have suggested that cursor-up should work like the prf key if one or
  331.       more characters have been typed.  Decided against this, because it
  332.       will confuse.  After all, why shouldn't it work like F3, instead?
  333.  
  334.       Added the 'also' key, which works in a similar way to the 'it' key.
  335.       Eg, TYPE FRED, <ALSO> JIM, thus <ALSO> repeats the TYPE command.
  336.       Currently using the F10 key for 'also'.  See also_proc.
  337.  
  338.       Added line to ALIAS I info to give number of aliases currently
  339.       defined, and the total number of places in the table.
  340.  
  341.       Pressing ESCape allows exit from recursive aliases.  This was easier
  342.       and safer than adding Ctrl-C checking.
  343.  
  344.       Released on cix in exe/alias 20.1.89.
  345.  
  346. 4.11  Fixed 2 places in ab_add proc, so that aliases of 7 characters or
  347.       more get truncated properly and added to the table in the right way.
  348.       Previously, the proc was not stepping over any unwanted lhs characters
  349.       that were over the lhs length limit.
  350.  
  351.       Also fixed routine at do_again: to put the correct number of characters
  352.       into the comparison buffer. 6-character aliases are now accepted, listed
  353.       and executed properly.
  354.  
  355.       Changed dates from 1988 to 1989.
  356.  
  357.       Environment block does not get freed if debug flag is set.  This lets
  358.       SMAP find the name of the loaded program.
  359.  
  360.       Sprinkled a few cld instructions around, to ensure that repeated
  361.       mov and sto instructions go in the right direction.
  362.  
  363.       Released on Cix as ALIAS411.ARC on 2 Jan 1989.
  364.  
  365. 4.10  Changed alias i text to talk about command completion and not parameter
  366.       recall.
  367.  
  368.       Released on Cix 30.12.88 as ALIAS410.ARC, containing just ALIAS.COM.
  369.  
  370. 4.03  Removed the extra lines in tinyedt that checked for the prf_trigger
  371.       key, and replaced them with an entry in cmndtbl.  This is the proper
  372.       way to do things, and it saves about 150 bytes.
  373.  
  374.       Made prf match with whatever the user has currently typed, rather than
  375.       waiting for a whole word to be typed.
  376.  
  377.       Fixed bug from earlier incarnations of the prf procedure that prevented
  378.       matches from being found in certain circumstances, by replacing the
  379.       charcount routine, that kept track of how many characters the user had
  380.       typed, with calls to bublcnt when required.  Simply incrementing a
  381.       counter after all calls to getc was not good enough, because it didn't
  382.       take into account things like presses of the del key.
  383.  
  384.       Changed help text entry for parameter recall to Command Completion,
  385.       which is more accurate.  Added ALIAS B command to help text, after
  386.       its previous, yet temporary, demotion to an undocumented command.
  387.  
  388.       Changed 2 INC SI commands in ab_buffer to calls to cmdinc.  This should
  389.       fix the problems that were happening with the alias b command.
  390.  
  391.       Added check for multiple presses of the prf trigger key, to bring
  392.       back repeated matches if there are any.  Multiple presses of the
  393.       key now cycle through all matches, then back to the first match
  394.       again.
  395.  
  396.       Added printregs proc.  Gets assembled only if DEBUG is defined as
  397.       non-zero.  Calling printregs prints the values of all the registers,
  398.       in ascii hex, on LPT1.
  399.  
  400. 4.02  Changed to_lower proc so that, instead of forcing all aliases to
  401.       lower case, we now force only the short forms.  The long forms,
  402.       ie the second string in an ALIAS A command, are now case sensitive.
  403.       The short forms are still forced to lower case, so you can not create
  404.       an alias called DA if there is an alias called da.
  405.  
  406. 4.01  Added overwrite mode facility to editor, cos all input was in
  407.       insert mode.  Added entry to cmndtbl, plus extra code to putin.
  408.       Also added ins_mode byte in data area, and inskey proc to toggle
  409.       the byte when the insert key is pressed.
  410.  
  411.       Changed hard-coded prf trigger key (SPACE character) to one defined
  412.       with an equate, so it can easily be changed.  Currently set to F4.
  413.  
  414. 4.00  Added PRF, Parameter Recall Facility.
  415.       Added code to dosedit routine to watch for first space char in
  416.       string, and call do_prf when it's found.  Doesn't allow the space
  417.       to be the first char.
  418.       Amended help text to include ALIAS X and ALIAS Y commands.
  419.       Lengthened command table to accept ALIAS X and ALIAS Y.
  420.       Added procs to process ALIAS X and ALIAS Y.
  421.       Added proc to AB_INFO to display current state of PRF.
  422.       Added do_prf proc to handle the display updating and command matching.
  423.       Do_prf checks for match and, if found, prf_disp updates display.
  424.  
  425.       Replaced the 01Ah byte, stored at the front of an alias table file,
  426.       with the value of prf_flag, so this flag now gets saved in the file.
  427.       To update an old data file, from a version of ALIAS less than
  428.       4.00, type ALIAS X or ALIAS Y to set prf preference, and re-save the
  429.       file with ALIAS W.
  430.  
  431.       Added display-a-white-space routine after ab_buffer to prevent
  432.       corruption of display.
  433.  
  434.       Removed ALIAS ? from the help screen, as a shorter help screen cures
  435.       the last ocurrence of the display colour bug.
  436.  
  437.       Fixed bug in code that constructed default data file name.  If file
  438.       was in root, an extra backslash was added.  Now works properly.
  439.  
  440.       Added DEBUG flag in equates.  If set, BIOS_BLIP gets assembled.
  441.  
  442.       Rewrote do_prf so that the command stack is searched in the correct
  443.       order, ie most current commands first.  Also takes account of commands
  444.       that may wrap around between top and bottom of the command stack.
  445.  
  446.       Added move_crsr proc to prf code so that cursor is placed in correct
  447.       position after prf facility is used.
  448.  
  449. 3.04  Changed alias.dat to upper case, so that it looks better when
  450.       printed by the alias i command.
  451.  
  452.       Removed DOSEDIT equate, that allowed a version of ALIAS to be 
  453.       assembled without the DOSEDIT module.  This is to prepare for the
  454.       parameter recall facility, which will only work when DOSEDIT is loaded,
  455.       as we need control over individual keys pressed.
  456.  
  457.       Removed the 'Command Line Editor Available' message from alias i
  458.       info, cos it's always available now.
  459.  
  460. 3.03  Rewrote help screen to be task-oriented rather than keystroke
  461.       oriented.  Token values changed to apply to new help screen.
  462.  
  463.       Removed a call to crlf, to stop leaving 2 blank lines after ALIAS W.
  464.  
  465.       If the default file is loaded at install time, a record of the current
  466.       directory is kept.  If an ALIAS W command is given, and no file is
  467.       specified, the default file written will be placed in the same directory
  468.       as the original file was loaded from.  If a filename IS given, it will
  469.       go in the current directory, or the one specified in the pathname on
  470.       the ALIAS W command.
  471.  
  472.       ALIAS R commands work the same.  If just ALIAS R is typed, and a
  473.       default file was loaded at install time, the ALIAS R command will read
  474.       from that same default file, with the same path.
  475.  
  476.       The ALIAS I command shows the full pathname of the current default
  477.       file.  Note that this default filename cannot be changed.
  478.  
  479.       Added small routine in INSTALL procedure to free the program's
  480.       copy of the environment strings.  This saves a few bytes of RAM
  481.       once the program is installed, though it does mean that programs such
  482.       as SMAP and RMAP will not be able to report the name of the program,
  483.       as the name is stored at the end of the environment string data.
  484.  
  485.       ALIAS303.ARC, containing just a COM file, released on Cix 18/11/88.
  486.       Will not give source code away from now on.
  487.  
  488. 3.02  Changed from Microsoft MASM 5.1 to OPTASM 1.5.  No changes at all
  489.       required for source code.  Assembles faster, and produces a .COM
  490.       file around 35 bytes smaller, by optimizing jump instructions.
  491.  
  492.       No OPTASM special features are used, in order to maintain MASM 5
  493.       compatibility.  This means that pushm and popm are not used, for
  494.       example.  OPTASM takes care of jumps being out of range, so there
  495.       may be a couple of these that need correcting if MASM is used.
  496.  
  497.       Fixed ab_buffer proc so that listings pause after each screen. Added
  498.       line to list_pause proc, to clear the counter when the list_proc
  499.       routine is called.
  500.  
  501.       Added disclaimer, and removed (c) symbol from help text.
  502.  
  503.       Replaced generic 'There is an error' message with a set of more
  504.       specific ones.  Procs added are invalid_letter, syntax_error,
  505.       exist_err and not_found.
  506.  
  507. 3.01  Fixed bugs caused by block-conversion of the NDE code to lower
  508.       case.  A few capital letters in quotes got changed to l/case, which
  509.       affected CMP instructions.
  510.  
  511.       Removed redundant message that used to be produced after the SORT
  512.       command had done its job.
  513.  
  514.       Changed ShrtStr from 2 to 0, so all strings are saved in DOSEDIT
  515.       buffer, even if they are only 1 char long.  This means that ALIAS B
  516.       gives you a true history of what you've typed recently.  There should
  517.       be an option of saving the history to file, but there isn't yet.
  518.  
  519.       Re-wrote ab_buffer proc so that strings get displayed in the
  520.       current colour, and not white.
  521.  
  522.       ALIAS301.ARC RELEASED SEPTEMBER 1988.
  523.       ARC FILE INCLUDES ALIAS.ASM AND ALIAS.COM.
  524.       DOC FILE FROM v1.31 NOT INCLUDED.  SEE THIS HISTORY SECTION INSTEAD.
  525.  
  526. 3.00  Added DOSEDIT-like facility.  This is now a standard feature of having
  527.       ALIAS loaded, and thus makes it ALIAS a superset of DOSEDIT.  Current
  528.       DOSEDIT users can be encouraged to replace DOSEDIT with ALIAS v3.00.
  529.  
  530.       At present the DOSEDIT code is based strongly on NDE, a Norton
  531.       DOSEDIT clone released as shareware on CompuServe a couple of years
  532.       ago.  This code will be modified and improved, though.
  533.  
  534.       The parameter recall facility as found in CED is not yet available
  535.       with ALIAS.  This will come in version 4 of ALIAS, hopefully.
  536.  
  537.       DOSEDIT flag added.  If false, program will assemble with old
  538.       get-string code, and will not include the DOS editor.  Saves around
  539.       3K of RAM in the file and the resident code.
  540.  
  541.       Changed int 10h calls in editor code to use bios_video macro.
  542.  
  543.       Added check at install time to permit loading under DOS version 4.x.
  544.  
  545.       Added ALIAS B command.  Only assembles if DOSEDIT is true.
  546.  
  547. 2.13  Added message at load time to say we're loading alias.dat.
  548.  
  549. 2.12  Fixed to_lower proc to only convert characters in the range A to Z.
  550.       (Note the capitals).  If ALL characters are converted, strange things
  551.       happen, eg a backslash becomes a pipe character.
  552.  
  553.       Entries in multiple commands can't have overrides.  
  554.       Eg, ALIAS A ZZ CD\FRED & ~TC stuffs CD\FRED into the buffer, and then
  555.       stuffs ~TC (ie, the override char gets stuffed as well.)  Also, ~A & B
  556.       results in A getting executed but not B.  These 'bugs' cured by
  557.       officially documenting the fact that overrides are only designed to
  558.       override a whole line, and that their use in any other place than the
  559.       1st char in a line, or the use of more than 1 override char in a line
  560.       will cause unpredictable results.
  561.  
  562. 2.11  Added some tokenising in the HELP text, so that phrases appearing
  563.       many times are included in the code only once. Size of .COM file was
  564.       reduced by 457 bytes, despite the additional code to process the tokens.
  565.  
  566.       Added crlf to start of list4 label, to prevent corruption of DOS
  567.       prompt if ALIAS L xxx failed to find specified entry in table.
  568.  
  569. 2.10  Added checking in replace_params and subst procs, to ensure that
  570.       we don't stuff too many characters into the ds:dx buffer.  The size
  571.       of the buffer is in ds:dx, placed before the function call.
  572.  
  573.       Fixed bug in list routine to handle 40h:84h being 0, in which case
  574.       screen length gets set to 25.
  575.  
  576.       Force the parameters of an ALIAS A command to lower case, to prevent
  577.       case-sensitive aliases being added to the table.
  578.  
  579.       Added routine after faking a get-string call, to iret if the user
  580.       simply presses RETURN.  In such a case, no more processing by ALIAS
  581.       is necessary.
  582.  
  583. 2.01  Added nesting facility.  You can have ALIAS A FA F A:*.*, where the
  584.       expanded alias is an alias command in its own right.
  585.  
  586.       Fixed bug in AB_ADD routine that checks whether an alias exists before
  587.       allowing one to be added to the table.  The check routine checked one
  588.       too few entries, so you could add an alias that had the same name as
  589.       the last one in the table.
  590.  
  591.       Changed list_pause routine to only pause if screen is really full
  592.       (ie, support EGA 43 lines).  Also, Press Any Key message is removed
  593.       from screeen when key pressed.
  594.  
  595.       Added get_vpage proc, so we now write to the current video page and
  596.       don't simply assume page 0.  Should really force video page to 0 if
  597.       we are in graphics mode, but who has a DOS prompt in graphics mode?!
  598.  
  599. 2.00  Added parameter facility. If F is abbreviated to DIR, then typing
  600.       F A: will be expanded to DIR A: and not just DIR.
  601.       This is done as follows.  When the user's string is first typed,
  602.       only the first word (up to a space) is used for deciding if an alias
  603.       exists.  The rest is just saved away in a buffer.  Once the alias
  604.       has been substituted, REPLACE_PARAMS is called to put those buffered
  605.       characters back where they belong and to update the length pointer
  606.       in ds:[dx+1].  In theory, the routine should ensure that the length
  607.       of the new string doesn't exceed that specified in [dx] and, if
  608.       it does, the string should be truncated.  This does not happen in
  609.       version 2.00.
  610.  
  611.       Note that replace_params only does something if the search for an
  612.       alias succeeds.  If the first word that a user types does not appear
  613.       in the table, replace_params does nothing.
  614.       Note that, in multi-statement lines, any parameters get appended to
  615.       THE LAST OF THE STATEMENTS ONLY.  So, if you have CLS & DIR, the
  616.       parameters would go on to the DIR but not the CLS.
  617.  
  618.       Added AB_ORDER proc to sort the alias table in RAM. This was originally
  619.       called by the ALIAS O command but I've changed things so that it gets
  620.       called automatically whenever the table changes.  This way, the table is
  621.       always kept alphabetical for the benefit of the user.  Because of this,
  622.       it would be better (and faster) if the ADD procedure looked for
  623.       spare table entries by starting from the bottom, but doing this is not
  624.       really important.
  625.  
  626.       Fixed colour bug.  Before, if an ALIAS command causing screen output
  627.       made the screen scroll, the DOS default attribute changed to ALIAS's
  628.       colour setting.  So, an ALIAS L that filled the screen with yellow text
  629.       would cause all subsequent DOS output to be in yellow until a CLS.
  630.       The cause of this is BIOS video function 0Eh (write TTY).  When it
  631.       scrolls the screen up, it gets the attributes for the new line from the
  632.       line above, which was the coloured text displayed by ALIAS.  Fixed by
  633.       adding a routine to put a white space at the start of a line, for
  634.       function 0Eh to find and copy.  This problem doesn't seem to occur if
  635.       ANSI.SYS is loaded - perhaps it handles scrolling in a better way.
  636.  
  637.       Expanded the LIST command to stop if screen is full and ask user to
  638.       press any key.  Essential if you have more than 24 aliases in table.
  639.  
  640.       Install routine now permits loading under DOS major version 2,3 or 10.
  641.       Version 10.0 is the DOS box of OS/2.
  642.  
  643.       Replaced int 10h calls with a macro that also preserves bp, cos of bug
  644.       in early IBM bios, that trashes bp during an int 10h call.
  645.  
  646. 1.31  Expand_from and ab_status flag bytes moved into the table area, so
  647.       they now get saved to disk with the table.
  648.       Disk_error_msg proc added.  DOS version check now looks for ver 2 or 3,
  649.       and not just >1. Prevents prog being used under DOS 4 or OS/2.
  650.  
  651.       ALIAS131.ARC (first ever release of ALIAS) RELEASED DECEMBER 1987.
  652.       ARC FILE CONTAINS JUST ALIAS.COM AND DOCUMENTATION.
  653.  
  654. 1.30  Added bp to list of registers in push_all and pop_all macros.
  655.       Added shift_left proc, so that leading spaces in user's input are now
  656.       handled as they would be if ALIAS were not installed,
  657.  
  658. 1.29  Changed method for checking whether ALIAS is resident.  Versions up to
  659.       1.28 used a signature.  The checking process involved searching all of
  660.       RAM for the signature.  This was slow, and also meant that, if a copy
  661.       of ALIAS.COM was kept on a ram disk, the signature would appear in
  662.       memory even if ALIAS was not loaded.
  663.       Version 1.29 intercepts int 21h function 35h (get interrupt vector).
  664.       Before passing control to the real function 35h routine, the fifth byte
  665.       of the inter-application communication area at 0040:00F4h is 
  666.       incremented.  Thus, a program simply needs to do a dummy call to func
  667.       35h and monitor the ICA byte, to see whether ALIAS is loaded or not.
  668.       The side-effect of this is that calls to function 35h will corrupt 
  669.       the ICA.  If this causes problems it can be fixed, though the very few
  670.       programs that actually use the ICA should be responsible enough to
  671.       keep a check on its integrity now and again!
  672.  
  673. 1.28  Display error message if invalid ALIAS command typed
  674.  
  675. 1.27  If only 1 parameter is specified in A command, error msg displayed.  If
  676.       the single parameter followed by a space, abbreviation is set up to
  677.       a null string and can be deleted with D.
  678.       Error message (no action taken) expanded to give help.
  679.  
  680. 1.26  Check with ALIAS L that user leaves a space between arg and ALIAS L
  681.       else machine hangs. Same goes for D and A command.
  682.  
  683. 1.25  Y or N typed to Are You Sure message gets echoed in correct colour
  684.  
  685. 1.24  Only Y,y,N,n allowed in response to 'Are you sure...' msg.
  686.       Alrdy_in message expanded.
  687.  
  688. 1.23  Fixed bug so that args specified in D and L command works in u/case too
  689.  
  690. 1.22  List command can now optionally take an argument. Zap_msg tidied up.
  691.       Confirmation required on f,r,w,z options.
  692.       Added disp_ch CR in echo proc, after echoing ']'.  Needed for Infocom
  693.       games.
  694.  
  695. 1.21  Echo_status saved with data files. 
  696.  
  697. 1.20  Alias commands can now be recalled with F3, just like any DOS command.
  698.       The ALIAS Z command can't, though, as the routine that puts the chars
  699.       back into the buffer for F3 to find doesn't get called because alias
  700.       has been de-installed.  Oh well, can't have everything I s'pose.
  701.  
  702. 1.11  Current colour gets saved with the table.
  703.  
  704. 1.10  Fixed colour bugs in ALIAS L and in show mode, where some parts
  705.       always displayed in white.
  706.  
  707. 1.00  First version of Alias.  Previously called ABR.  Commands changed from
  708.       AB to ALIAS.  Default filename changed from DEFAULT.ABR to ALIAS.DAT
  709.  
  710.         |                             ; end of comment
  711.  
  712. ; -----------------------------------------------------------------------
  713. ;                           M A C R O S
  714. ; -----------------------------------------------------------------------
  715. ;  
  716. ;
  717. show    macro     string                    ; Display a string using
  718.         push      ax                        ; a DOS call.
  719.         push      dx
  720.         push      ds
  721.  
  722.         push      cs
  723.         pop       ds
  724.         mov       ah,9
  725.         mov       dx,offset cs:string
  726.         int       21h
  727.  
  728.         pop       ds
  729.         pop       dx
  730.         pop       ax
  731. endm
  732. ;
  733. push_m  macro arglist
  734.               irp      register,<arglist>
  735.               push     register
  736.               endm
  737.         endm
  738. ;
  739. pop_m   macro arglist
  740.               irp      register,<arglist>
  741.               pop      register
  742.               endm
  743.         endm
  744. ;
  745. disp_ch macro char
  746.         push_m <ax,dx>
  747.         mov   dl,char
  748.         mov   ah,2
  749.         int   21h
  750.         pop_m <dx,ax>
  751.         endm
  752. ;
  753. push_all      macro
  754.               push_m <ax,bx,cx,dx,di,si,es,ds,bp>
  755.               endm
  756. ;
  757. pop_all macro
  758.         pop_m <bp,ds,es,si,di,dx,cx,bx,ax>
  759.         endm
  760. ;
  761. bios_video    macro
  762.         push  bp
  763.         int   10h
  764.         pop   bp
  765.         endm
  766. ;
  767. ; -----------------------------------------------------------------------
  768. ;                          E Q U A T E S
  769. ; -----------------------------------------------------------------------
  770. VERS        equ   '4.50'              ; Current version number.
  771.                                       ; Note that this is the only place
  772.                                       ; where the version number is quoted
  773.                                       ; literally.
  774.  
  775. DEBUG       equ   0                   ; Assemble debug procs if <> 0
  776.                                       ; Also, don't free environment block
  777. ONLINE_HELP equ   1                   ; Only assemble help text if set
  778.  
  779. RSIZE     equ   (init-start)/16+17      ; number of resident paragraphs
  780. CR        equ   0Dh                     ; carriage return character
  781. LF        equ   0Ah                     ; line feed character
  782. EOM       equ   0                       ; message terminator for internal
  783.                                         ; display routines.
  784. DOS_EOM   equ   '$'                     ; message terminator for strings
  785.                                         ; displayed by DOS functions.
  786. BS        equ   08                      ; backspace
  787. LETTER    equ   byte ptr cs:command_letter 
  788. SPACE     equ   20h
  789. WHITE     equ   7                       ; attribute value
  790.  
  791. ; The following 3 values define the size of the alias table
  792.  
  793. LHS_LEN equ   06                      ; length of lhs in table entry
  794. RHS_LEN equ   70                      ; length of rhs
  795. TBL_LEN equ   30                      ; no of entries in table
  796. ;
  797. OVERRIDE      equ '~'                 ; override character for commands
  798. SEPARATOR     equ '&'                 ; char between cmds on multi-cmd lines
  799.  
  800.  
  801. ; Extra DOSEDIT equates
  802.  
  803. PRF_TRIGGER   equ    0142h            ; F8 key
  804. IT_KEY        equ    0143h            ; F9 key
  805. ALSO_KEY      equ    0144h            ; F10 key
  806. MaxSWdt       equ    134              ;max screen width
  807. MaxLin        equ    140              ;max line length to edit
  808. CmdLen        equ    1500             ;number of char for previous commands
  809. ShrtStr       equ    0                ;length of strings too short to save
  810. TAB           equ    09H              ;ASCII tab
  811. ESCAPE        equ    1BH              ;ASCII escape
  812. HomeKey       equ    0147H            ;home key
  813. UpArrw        equ    0148H            ;up arrow key
  814. LtArrw        equ    014BH            ;left arrow key
  815. RtArrw        equ    014DH            ;right arrow key
  816. EndKey        equ    014FH            ;end key
  817. DnArrw        equ    0150H            ;down arrow key
  818. DelKey        equ    0153H            ;delete key
  819. CntLf         equ    0173H            ;control left arrow key
  820. CntRt         equ    0174H            ;control right arrow key
  821. AltW          equ    0111H            ;ALT W key
  822. AltL          equ    0126H            ;ALT L key
  823. AltK          equ    0125H            ;ALT K key
  824. AltU          equ    0116H            ;ALT U key
  825. F1Key         equ    013BH            ; F1 Key.
  826. F3Key         equ    013DH            ;F3 function key
  827. F6Key         equ    0140H            ; F6 key.
  828. PGUPKEY       equ    0149H            ; PgUp Key
  829. PGDNKEY       equ    0151H            ; PgDn Key
  830. CNTL          equ    40H              ;difference between alpha and control
  831. Insert        equ    0152h            ;Insert key
  832.  
  833. ; end of dosedit equates
  834.  
  835. ; -----------------------------------------------------------------------
  836. ;                   S T A R T   O F   M A I N   C O D E
  837. ; -----------------------------------------------------------------------
  838. code    segment
  839.         assume     cs:code,ds:code,es:nothing
  840.         org   100h
  841.         ;
  842. start:  jmp   init                    ; init code at end of res section
  843.         ;
  844. private db  CR
  845.         db  'ALIAS v',VERS,' - (c) Robert Schifreen.',1ah
  846.         ;
  847. intent:                               ; DOS function 0Ah comes here now
  848.         ;
  849.  
  850.         push  ax                      ; first, save the flags reg
  851.         pushf                         ; save flags on stack...
  852.         pop   ax                      ; ...and retrieve into ax
  853.         mov   cs:save_flags,ax
  854.         pop   ax
  855.  
  856.         cmp   ah,0ah                  ; is this a 'get string' instruction?
  857.         je    go_on                   ; continue if it is
  858.  
  859.         cmp   ah,35h                  ; intercept get-int-vector to check for
  860.                                       ; alias being resident.
  861.         je    func35
  862.         jmp   exec                    ; else jump far to abort
  863.         ;
  864.  
  865.  
  866. func35:                               ; we have found a call to function 35h.
  867.                                       ; Increment byte 0040:00F4h as a sign
  868.                                       ; that ALIAS is resident.
  869.         push  ds
  870.         push  ax
  871.         mov   ax,40h
  872.         mov   ds,ax                   ; ds points to ICA segment
  873.         inc   byte ptr ds:0f4h        ; increment 5th byte of ICA
  874.         pop   ax
  875.         pop   ds
  876.         jmp   exec                    ; and go to real int 21h routine with
  877.                                       ; everything intact.
  878.  
  879. go_on:
  880.         ; 
  881.         cmp   cs:do_kb_str,0          ; do we want to restore kbd buffer?
  882.         je    no_restore_kbd          ; if not, then don't
  883.         call  restore_buffer          ; put back chars so F3 can find them
  884.         mov   cs:do_kb_str,0          ; clear the flag now it's dealt with
  885.  
  886. no_restore_kbd:
  887.  
  888.         push  bp                      ; The first time that the new int 21h 
  889.         push  ax                      ; handler is called, this routine saves
  890.         mov   ax,cs:command_cs        ; CS and IP values that called it. This
  891.         cmp   ax,0                    ; will be the location in COMMAND.COM
  892.         jne   csip_saved              ; that called it.When other strings are
  893.         mov   bp,sp                   ; processed we can get CS and IP values
  894.         mov   ax,ss:[bp+6]            ; from stack (pushed by INT) & cmp
  895.         mov   cs:command_cs,ax        ; them with the stored ones.  If they
  896.         mov   ax,ss:[bp+4]            ; match,string being looked at was
  897.         mov   cs:command_ip,ax        ; entered from DOS prompt. If not, str 
  898.         ;
  899. csip_saved:                           ; must have come from another prog.
  900.         ;
  901.         pop   ax
  902.         pop   bp
  903.         ;
  904.         push  ax                      ; was string typed at the DOS prompt?
  905.         push  bx                      ; (See above for how to find out.)
  906.         push  bp
  907.         mov   bp,sp
  908.         mov   ax,ss:[bp+8]            ; get CS value that called us.
  909.         mov   bx,cs:command_cs        ; get saved CS value
  910.         cmp   ax,bx                   ; are they the same?
  911.         jne   wrong_csip              ; abort if not
  912.         ;
  913.         mov   ax,ss:[bp+6]            ; get IP value that called us
  914.         mov   bx,cs:command_ip        ; get saved IP value
  915.         cmp   ax,bx                   ; same?
  916.         jne   wrong_csip              ; abort if not equal
  917.         jmp   csip_valid              ; continue processing if OK
  918.         ;
  919. wrong_csip:                           ; We were not called from COMMAND.COM
  920.                                       ; so just get string and return
  921.         ;
  922.         pop   bp
  923.         pop   bx
  924.         pop   ax
  925.         ;
  926.                                       ; although the string was not 
  927.                                       ; typed at the DOS prompt, if
  928.                                       ; expand_from = 1 then global 
  929.                                       ; expansion is required so jmp to
  930.                                       ; csip_valid anyway
  931.         cmp   cs:expand_from,1
  932.         je    csip_valid2
  933.         ;
  934.         cmp   cs:multi_line_outstanding,0
  935.         je    no_need   
  936.         jmp   do_multi_line
  937.         ;
  938. no_need:
  939.         ;         
  940.         call  get_string_from_kbd     ; else fake a real 'get string' call
  941.         call  restore_flags           ; replace flags saved on entry
  942.         iret                          ; and return to caller of INT 21h
  943.  
  944. csip_valid:                           ; CS and IP values correct. Look for ~
  945.         pop   bp                      ; tidy up the stack
  946.         pop   bx
  947.         pop   ax      
  948.                                       ; Is there part of a multi-statement
  949.                                       ; line that has not been passed to DOS?
  950.                                       ; If so, don't read keyboard but go    
  951.                                       ; straight to correct routine.
  952.  
  953. csip_valid2:                          ; come here if global.
  954.         ;
  955.         cmp   cs:multi_line_outstanding,0 
  956.         je    no_multi_line           ; if 0, no multi-line in process
  957.         jmp   do_multi_line
  958.         ;
  959. no_multi_line:
  960.         ;
  961.         call  get_string_from_kbd     ; fake a real 'get string' call
  962.  
  963.         push_m <bp,ax>
  964.         mov    bp,dx
  965.         mov    ah,byte ptr ds:[bp+1]  ; get length of string entered
  966.         cmp    ah,0                   ; do nothing if user just pressed RETURN
  967.         jne    not_zerolen2
  968.         jmp    short zero3
  969.  
  970. not_zerolen2:
  971.  
  972.         cmp    ah,1                   ; is string only 1 char long?
  973.         jne    not_zerolen
  974.         mov    ah,byte ptr ds:[bp+2]
  975.         cmp    ah,SEPARATOR           ; and is that 1 char an ampersand?
  976.         jne    not_zerolen            ; forget it if so
  977.         mov    byte ptr ds:[bp+1],0
  978.         mov    byte ptr ds:[bp+2],CR  ; else clear the ampersand
  979. zero3:
  980.         pop_m  <ax,bp>
  981.         call   restore_flags
  982.         iret                          ; There's nowt for us to do
  983.  
  984. not_zerolen:
  985.  
  986.         pop_m <ax,bp>
  987.         push  ax
  988.         push  bp
  989.         mov   bp,dx
  990.         mov   ah,ds:[bp+2]            ; get 1st char in string
  991.         cmp   ah,override             ; is it the override character?
  992.         jne   find_ab                 ; if not, proceed 
  993.         mov   byte ptr ds:[bp+2],' '  ; else, replace ~ with space
  994.         pop   bp
  995.         pop   ax
  996.         ;
  997.         call  restore_flags
  998.         iret                          ; and return to caller
  999.         ;
  1000. find_ab:
  1001.         ;
  1002.         pop   bp
  1003.         pop   ax
  1004.  
  1005. find_ab2:                             ; Come here after expanding an alias,
  1006.                                       ; thus allowing nesting.
  1007.  
  1008.  
  1009.         push   ax                     ; Allow ESC to abort recursive aliases
  1010.         push   dx
  1011.  
  1012. special_key:
  1013.  
  1014.         mov    ah,6                   ; is there a char waiting?
  1015.         mov    dl,0FFh
  1016.         int    21h
  1017.         jz     no_break               ; no key is waiting
  1018.         cmp    al,0
  1019.         je     special_key
  1020.         cmp    al,ESCAPE              ; is key ESCAPE?
  1021.         jne    no_break
  1022.         pop    dx
  1023.         pop    ax
  1024.         call   restore_flags          ; ESC pressed.  Tidy up.
  1025.         push   bp
  1026.         mov    bp,dx
  1027.         mov    byte ptr ds:[bp+1],0   ; Clear the buffer, so passing DOS
  1028.         mov    byte ptr ds:[bp+3],CR  ; an empty command string.
  1029.         pop    bp
  1030.         iret
  1031.  
  1032. no_break:
  1033.  
  1034.         pop    dx
  1035.         pop    ax
  1036.  
  1037.                                       ; Before operating on user's string,
  1038.                                       ; remove any leading spaces.
  1039.         call  shift_left
  1040.  
  1041.                                       ; If the first 6 characters in the
  1042.                                       ; string are 'ALIAS 'then do requested
  1043.                                       ; command. If not, search table and
  1044.                                       ; replace string if required.
  1045.                                       ; 1st string at ds:si
  1046.         push_m <si,ds,es,di,cx,ax>
  1047.         mov   si,dx
  1048.         add   si,2
  1049.         mov   ax,cs
  1050.         mov   es,ax
  1051.         mov   ax,offset cs:match
  1052.         mov   di,ax                   ; 2nd string at es:di
  1053.         mov   cx,6                    ; compare 6 bytes
  1054.         cld
  1055.         repe  cmpsb
  1056.         je    ab_found
  1057.         ;
  1058.         mov   si,dx                   ; if not found, try looking for upper
  1059.         add   si,2                    ; case version too
  1060.         mov   di,offset cs:match_u_case
  1061.         mov   cx,6
  1062.         repe  cmpsb
  1063.         je    ab_found
  1064.         ;
  1065.         jmp   not_ab                  ; jump if alias command not typed
  1066.         ;
  1067. ab_found:
  1068.         ;
  1069.         pop_m <ax,cx,di,es,ds,si>
  1070.  
  1071.                                       ; an alias command was typed, so find 
  1072.                                       ; out what one it is, and act on it
  1073.         push  ax
  1074.         push  bp
  1075.         mov   bp,dx
  1076.         mov   ah,byte ptr ds:[bp+1]   ; string must be 7 chars long 
  1077.         cmp   ah,7
  1078.         pop   bp
  1079.         pop   ax
  1080.         jnb   length_correct
  1081.         jmp   bye
  1082.         ;
  1083. length_correct:
  1084.         ;
  1085.         push  ax
  1086.         push  bp
  1087.         mov   bp,dx
  1088.         mov   ah,byte ptr ds:[bp+8]   ; get 8th char of string
  1089.         or    ah,00100000b            ; force to lower case
  1090.         mov   cs:command_letter,ah    ; save it
  1091.         pop   bp
  1092.         pop   ax
  1093.         ;
  1094.                                       ; the following list of CMP's may well
  1095.                                       ; be bad programming practice, but it
  1096.                                       ; is easier to follow than a jump
  1097.                                       ; table, and is shorter too!
  1098.  
  1099.  
  1100.         cmp   letter,'?'
  1101.         jne   x1
  1102.         call  ab_help
  1103.         jmp bye
  1104. x1:     cmp   letter,'a'
  1105.         jne   x2
  1106.         call  ab_add
  1107.         call  ab_order
  1108.         jmp bye
  1109. x2:     cmp   letter,'d'
  1110.         jne   x3
  1111.         call  ab_delete
  1112.         call  ab_order
  1113.         jmp bye
  1114. x3:     cmp   letter,'l'
  1115.         jne   x4
  1116.         call  ab_order
  1117.         call  ab_list
  1118.         jmp bye
  1119. x4:     cmp   letter,'w'
  1120.         jne   x5
  1121.         call  ab_order
  1122.         call  ab_write
  1123.         jmp bye
  1124. x5:     cmp   letter,'r'
  1125.         jne   x6
  1126.         call  ab_read
  1127.         jmp bye
  1128. x6:     cmp   letter,'c'
  1129.         jne   x7
  1130.         call  ab_colour
  1131.         jmp bye
  1132. x7:     cmp   letter,'n'
  1133.         jne   x8
  1134.         call  ab_none
  1135.         jmp bye
  1136. x8:     cmp   letter,'i'
  1137.         jne   x9
  1138.         call  ab_info
  1139.         jmp bye
  1140. x9:     cmp   letter,'f'
  1141.         jne   xa
  1142.         call  ab_flush
  1143.         jmp bye
  1144. xa:     cmp   letter,'p'
  1145.         jne   xb
  1146.         call  ab_prompt
  1147.         jmp bye
  1148. xb:     cmp   letter,'g'
  1149.         jne   xc
  1150.         call  ab_global
  1151.         jmp bye
  1152. xc:     cmp   letter,'s'
  1153.         jne   xd
  1154.         call  ab_show
  1155.         jmp bye
  1156. xd:     cmp   letter,'b'
  1157.         jne   xe
  1158.         call  ab_buffer
  1159.         jmp   bye
  1160. xe:     cmp   letter,'h'                  
  1161.         jne   xf
  1162.         call  ab_hide
  1163.         jmp bye
  1164. xf:     cmp   letter,'h'                  ; unused dummy. SPARE.
  1165.         jne   xg
  1166.         call  ab_hide
  1167.         jmp bye
  1168. xg:     cmp   letter,'h'                  ; unused dummy. SPARE
  1169.         jne   xh
  1170.         call  ab_hide
  1171.         jmp bye
  1172. xh:     cmp   letter,'z' 
  1173.         jne   xi
  1174.         jmp   ab_zap
  1175. xi:     call  invalid_letter
  1176.  
  1177.  
  1178. bye:                                  ; come back here if user says "No"
  1179.                                       ; when asked if sure about Zap
  1180.  
  1181.         push  bp
  1182.         mov   bp,dx
  1183.  
  1184.         push  ax                      ; save details before overwriting str,
  1185.                                       ; so they can be retrieved when this
  1186.                                       ; int handler is called again. Allows
  1187.                                       ; alias cmds to be recalled with F3.
  1188.         mov   al,ds:[bp+1]        
  1189.         mov   byte ptr cs:kb_str_len,al ; save length of string
  1190.         mov   al,ds:[bp+2]
  1191.         mov   byte ptr cs:kb_str_ch1,al ; save 1st char 
  1192.         pop   ax
  1193.  
  1194.         mov   byte ptr cs:do_kb_str,1 ; flag to say put back values
  1195.         mov   byte ptr ds:[bp+1],0    ; set length to 0 to stop ALIAS cmd
  1196.                                       ; being executed by DOS
  1197.         mov   byte ptr ds:[bp+2],CR   ; put c/r terminator in buffer too
  1198.         pop   bp
  1199.         ;
  1200.         call  restore_flags
  1201.         iret
  1202.         ;
  1203. not_ab:
  1204.         ;
  1205.  
  1206.         pop_m <ax,cx,di,es,ds,si>
  1207.  
  1208.                                       ; No ALIAS command typed. Search
  1209.                                       ; table and substitute if necessary
  1210.  
  1211.         cmp   cs:[ab_status],0        ; don't substitute if aliases off
  1212.         je    back_to_dos
  1213.         jmp   turned_on
  1214.  
  1215. back_to_dos:
  1216.  
  1217.         call  restore_flags
  1218.         iret
  1219.  
  1220. turned_on:                            ; aliases are not off so continue
  1221.  
  1222.         ;
  1223.         mov   byte ptr cs:nest_flag,0 ; set if expansion takes place
  1224.         push  bp
  1225.         mov   bp,dx
  1226.         cmp   byte ptr ds:[bp+1],0    ; get length of user's string
  1227.                                       ; if it's zero, abort.
  1228.         ;
  1229.         pop   bp
  1230.         je    too_long                ; abort if it is
  1231.         jmp   length_ok               ; otherwise OK to continue
  1232.  
  1233. too_long:
  1234.  
  1235.         call  copy_to_psp
  1236.         jmp   ok_to_cont2
  1237.  
  1238.  
  1239. length_ok:                            ; fill buffer with 0's
  1240.  
  1241.         push_m <ax,es,di,cx>
  1242.         cld
  1243.         mov   ax,cs       
  1244.         mov   es,ax
  1245.         mov   al,0h
  1246.         mov   di,offset cs:buffer
  1247.         mov   cx,LHS_LEN
  1248.         rep   stosb
  1249.         pop_m <cx,di,es,ax>
  1250.                                       ; Now put the string at ds:dx 
  1251.                                       ; into the buffer,
  1252.                                       ; up to (but not including) the 1st
  1253.                                       ; space char
  1254.         push_m <ax,bp,si,es,cx>
  1255.         mov   bp,0                    ; set count to 0
  1256.         mov   si,dx
  1257.  
  1258. do_again:
  1259.  
  1260.         mov   ah,ds:[si+bp+2]         ; get count'th char from user's string
  1261.         cmp   ah,SPACE                ; is it a space
  1262.         je    buffer_filled           ; jump if it is
  1263.         cmp   ah,CR                   ; is it CR (= end of string)
  1264.         je    buffer_filled           ; jump as though space was found
  1265.         or    ah,00100000b            ; force char to lower case as in table
  1266.         mov   cs:[buffer+bp],ah       ; put string in buffer
  1267.         inc   bp                      ; increment counter
  1268.         cmp   bp,LHS_LEN              ; all done?
  1269.         jne   do_again                ; loop if not
  1270.         ;
  1271. buffer_filled:
  1272.         ;
  1273.                                       ; We've taken the first word in the
  1274.                                       ; string.  Now take the remainder of the
  1275.                                       ; string and put it in the parameter
  1276.                                       ; buffer, for adding on to the replaced
  1277.                                       ; string after the alias has been
  1278.                                       ; substituted.
  1279.  
  1280.         push_m <di,ax,si,bp>
  1281.         mov    di,offset cs:param_buff  ; adr of buffer
  1282.  
  1283. param1:
  1284.  
  1285.         mov   ah,byte ptr ds:[si+bp+2]  ; get next char from user
  1286.         mov   byte ptr cs:[di],ah       ; put char in buffer and leave
  1287.                                         ; CR at end as terminator
  1288.         cmp   ah,CR
  1289.         je    param_done
  1290.         inc   di
  1291.         inc   si
  1292.         jmp   short param1
  1293.  
  1294. param_done:
  1295.  
  1296.         pop_m  <bp,si,ax,di>
  1297.  
  1298.         pop_m <cx,es,si,bp,ax>
  1299.  
  1300.                                       ; user's string, padded with 0's, is in
  1301.                                       ; buffer, ready to compare to
  1302.                                       ; table entries.      
  1303.  
  1304.         push_m <ax,bx,ds,si,es,di,cx>
  1305.         mov   bh,1                    ; count 30 comparisons
  1306.         mov   di,offset cs:ab_table   ; es:di is the ab_table
  1307.   
  1308. find_match:
  1309.  
  1310.         mov   ax,cs                   ; ds:si is buffer
  1311.         mov   ds,ax
  1312.         mov   si,offset cs:buffer
  1313.         mov   ax,cs
  1314.         mov   es,ax
  1315.         ;
  1316.         mov   cx,LHS_LEN              ; compare for 6 characters
  1317.         repe  cmpsb
  1318.         jne   oops
  1319.         jmp   match_found
  1320.  
  1321. oops:
  1322.  
  1323.         inc   bh                      ; no match found so loop again
  1324.         cmp   bh,TBL_LEN + 1
  1325.         je    no_luck
  1326.         add   di,RHS_LEN + 1          ; jump to next entry
  1327.         add   di,cx                   ; and skip over unchecked characters
  1328.         jmp   find_match              ; from previous pass through loop
  1329.  
  1330. no_luck:
  1331.  
  1332.         pop_m <cx,di,es,si,ds,bx,ax>
  1333.  
  1334.         call  copy_to_psp
  1335.         jmp   ok_to_cont2
  1336.  
  1337. match_found:
  1338.         
  1339.         mov   byte ptr cs:nest_flag,1 ; an expansion took place
  1340.         mov   cs:match_pos,di
  1341.         pop_m <cx,di,es,si,ds,bx,ax>
  1342.                                       ; the position in ab_table at which
  1343.                                       ; the matching string starts, is now
  1344.                                       ; in match_pos.
  1345.                                       ; The string at cs:match_pos 
  1346.                                       ; must be copied
  1347.                                       ; to ds:dx+2. must put match_len
  1348.                                       ; in ds:dx+1.
  1349.         push  ax                         
  1350.         mov   ax,cs:match_pos
  1351.         mov   cs:multi_start,ax       ; set start address to match_pos
  1352.         pop   ax
  1353.  
  1354. do_multi_line:  
  1355.  
  1356.                                       ; Although we have come here, if 
  1357.                                       ; global commands are not set and
  1358.                                       ; the call was not from the DOS
  1359.                                       ; prompt, return to read keybd
  1360.                                       ; instead.  This will make commands
  1361.                                       ; like DEBUG & DIR work properly,
  1362.                                       ; so that it will enter debug, pass
  1363.                                       ; control to the keyboard and then
  1364.                                       ; do a DIR after exiting debug. This
  1365.                                       ; assumes that global expansion is
  1366.                                       ; not set.  If it is, the DIR gets
  1367.                                       ; passed to debug.
  1368.         push_m <ax,bx,bp>
  1369.         mov   bp,sp 
  1370.         mov   ax,ss:[bp+8]  
  1371.         mov   bx,cs:command_cs 
  1372.         cmp   ax,bx 
  1373.         jne   not_from_prompt 
  1374.         mov   ax,ss:[bp+6]  
  1375.         mov   bx,cs:command_ip 
  1376.         cmp   ax,bx     
  1377.         jne   not_from_prompt 
  1378.         jmp   ok_to_continue 
  1379.  
  1380. not_from_prompt:
  1381.  
  1382.         pop_m <bp,bx,ax>
  1383.         cmp   byte ptr cs:expand_from,1
  1384.         je    ok_to_cont2
  1385.         jmp   no_multi_line
  1386.  
  1387. ok_to_continue:
  1388.  
  1389.         pop_m <bp,bx,ax>
  1390.         
  1391. ok_to_cont2:
  1392.  
  1393.         mov   cs:multi_len,0          ; length of string = 0
  1394.         push_all
  1395.         cld
  1396.         push  cs
  1397.         pop   ds
  1398.         mov   si,cs:multi_start       ; lodsb works with ds:si
  1399.  
  1400. multi1:
  1401.  
  1402.         lodsb                         ; get char from string
  1403.         cmp   al,0                    ; end of string reached?
  1404.         je    null_found
  1405.         cmp   al,SEPARATOR            ; multiple command separator?
  1406.         je    ampersand_found
  1407.         mov   bh,cs:multi_len         ; inc length of string & get next char
  1408.         inc   bh
  1409.         mov   cs:multi_len,bh
  1410.         jmp   multi1
  1411.  
  1412. null_found:                           ; end of string found so put into ds:dx
  1413.  
  1414.         pop_all
  1415.         push  ax
  1416.         mov   ax,cs:multi_start
  1417.         mov   cs:match_pos,ax
  1418.         mov   ah,cs:multi_len
  1419.         mov   cs:match_len,ah
  1420.         pop   ax
  1421.         mov   byte ptr cs:multi_line_outstanding,0
  1422.         call  subst                   ; put string from alias table into ds:dx
  1423.         call  expand_percents         ; If we put any % signs into ds:dx
  1424.                                       ; buffer then replace with parameters.
  1425.         call  restore_flags
  1426.         call  echo
  1427.  
  1428.                                       ; We are done.  However, instead of just
  1429.                                       ; IRETing, check to see if an expansion
  1430.                                       ; took place.  If it did, go round and
  1431.                                       ; check again, to allow nesting.
  1432.  
  1433.         cmp    byte ptr cs:nest_flag,1
  1434.         jne    no_nest
  1435.         jmp    find_ab2
  1436.  
  1437. no_nest:                              ; If no expansion took place, don't need
  1438.                                       ; to go round again.
  1439.  
  1440.         iret
  1441.  
  1442. ampersand_found: 
  1443.  
  1444.                                       ; A multiple-command-line separator 
  1445.                                       ; found.  Set starting position to
  1446.                                       ; 1st char after the ampersand, 
  1447.                                       ; so we know where to start from next
  1448.                                       ; time.  Then set the flag so that
  1449.                                       ; we come straight here next time
  1450.                                       ; that the 'get string' interrupt
  1451.                                       ; gets called, to put the next part
  1452.                                       ; of the multi-command line into the
  1453.                                       ; kbd buffer.
  1454.  
  1455.         pop_all
  1456.         push  ax 
  1457.         mov   ax,cs:multi_start 
  1458.         mov   cs:match_pos,ax 
  1459.         mov   ah,cs:multi_len 
  1460.         mov   cs:match_len,ah 
  1461.         pop   ax              
  1462.         mov   byte ptr cs:multi_line_outstanding,1
  1463.         call  subst                   ; Put string from alias table into ds:dx
  1464.         call  expand_percents         ; Expand any percent characters that
  1465.                                       ; were copied from alias table by SUBST.
  1466.         push  ax
  1467.         mov   ah,0
  1468.         mov   al,cs:multi_len
  1469.         add   ax,cs:multi_start
  1470.         inc   ax 
  1471.         mov   cs:multi_start,ax
  1472.         pop   ax
  1473.  
  1474.         call  echo
  1475.         call  restore_flags
  1476.         iret
  1477. ; -----------------------------------------------------------------------
  1478. ;                        P R O C E D U R E S
  1479. ; -----------------------------------------------------------------------
  1480. restore_flags proc                    ; restore flags register before iret
  1481.         push   ax   
  1482.         mov    ax,cs:save_flags
  1483.         push   ax
  1484.         popf
  1485.         pop    ax
  1486.         ret
  1487. restore_flags endp
  1488. ;
  1489. get_vpage proc                        ; get current video page into bh, so
  1490.                                       ; that we use the current video page
  1491.                                       ; for screen I/O.
  1492.         push ax
  1493.         push bx
  1494.         push cx
  1495.         push dx
  1496.         push si
  1497.         push di
  1498.         mov   ah,0fh
  1499.         BIOS_VIDEO                    ; page is in bh
  1500.         pop  di
  1501.         pop  si
  1502.         pop  dx
  1503.         pop  cx
  1504.         pop  ax                       ; gets old BX without destroying new bh
  1505.         mov  bl,al                    ; restore old bl
  1506.         pop  ax                       ; restore old ax
  1507.         ret
  1508.  
  1509. get_vpage  endp
  1510. ;
  1511. crlf    proc                          ; display carriage return and linefeed
  1512.         disp_ch CR 
  1513.         disp_ch LF
  1514.         ret
  1515. crlf    endp
  1516. ;
  1517. are_you_sure      proc                ; asks user "Are you sure you want to?"
  1518.                                       ; Sets confirm to 1 if user hits Y or y,
  1519.                                       ; or sets to 0 otherwsie.  All 
  1520.         push_all                      ; registers preserved.
  1521.         mov   bl,byte ptr cs:colour 
  1522.         mov   si,offset cs:sure_msg
  1523.         call  disp_str_colour         ; display message in current colour
  1524.  
  1525. sure1:
  1526.  
  1527.         mov   ah,8                    ; get key (without echo) into al.
  1528.         int   21h
  1529.         cmp   al,0                    ; if it's a 2-byte code,
  1530.         je    sure1                   ; then go round again.
  1531.         or    al,00100000b            ; make character lower case
  1532.  
  1533.         push_m <ax,bx,cx,si,di>
  1534.         mov   bl,cs:colour            ; get current colour
  1535.         call  get_vpage               ; current page into bh
  1536.         mov   cx,1                    ; do it once
  1537.         mov   ah,9
  1538.         BIOS_VIDEO                    ; echo Y or N to console in correct
  1539.                                       ; colour
  1540.         pop_m <di,si,cx,bx,ax>
  1541.  
  1542.         cmp   al,'y'                  ; Y or y pressed?
  1543.         jne   not_y
  1544.         mov   byte ptr cs:confirm,1   ; set flag to show Y or y typed
  1545.         jmp   short sure_done
  1546. not_y:  cmp   al,'n'
  1547.         jne   sure1                   ; get key again if not y or n
  1548.         mov   byte ptr cs:confirm,0   ; set flag to show Y or y not typed
  1549.  
  1550. sure_done:
  1551.         pop_all
  1552.         call  crlf
  1553.  
  1554.         push_m  <si,di,cx,bx,ax>
  1555.         mov     ah,9
  1556.         mov     al,SPACE
  1557.         mov     bl,WHITE               ; attrib
  1558.         call    get_vpage              ; get vpage into bh
  1559.         mov     cx,1
  1560.         BIOS_VIDEO
  1561.         pop_m   <ax,bx,cx,di,si>
  1562.  
  1563.         ret
  1564. are_you_sure      endp
  1565. ;
  1566. shift_left        proc                ; Remove any leading spaces in the
  1567.                                       ; string at ds:dx+2.  Adjust length of
  1568.                                       ; string in byte at ds:dx+1, to reflect
  1569.                                       ; the number of spaces removed.
  1570.  
  1571.          push_all
  1572.          mov      ah,0                ; we only use al.
  1573.          mov      bp,dx               ; start of func 0Ah's buffer
  1574.          add      bp,2                ; skip to 1st char of user's input
  1575.          mov      si,0                ; user si as a counter
  1576.  
  1577. shift1:
  1578.  
  1579.          mov      al,ds:[bp]          ; get a char from user's string
  1580.          cmp      al,SPACE
  1581.          jne      not_a_space
  1582.          inc      si                  ; inc counter for no. of spaces found
  1583.          inc      bp                  ; point to next char in string
  1584.          jmp      short shift1        ; and round we go again
  1585.  
  1586. not_a_space:                          ; ah holds no. of leading spaces found
  1587.  
  1588.          cmp     si,0                 ; any spaces found?
  1589.          je      shift_done           ; we're finished if none found
  1590.          mov     bp,dx                ; point to start of string again
  1591.          add     bp,2
  1592.          add     bp,si                ; jump over spaces to 1st non-space char
  1593.  
  1594. shift2:
  1595.  
  1596.          mov     al,ds:[bp]           ; get char
  1597.          sub     bp,si                ; adjust bp
  1598.          mov     byte ptr ds:[bp],al  ; move char back, Can't have [bp-si],
  1599.                                       ; hence the above subtraction
  1600.          add     bp,si                ; adjust bp back again
  1601.          inc     bp
  1602.          cmp     al,CR                ; have we just shifted a CR?
  1603.          jne     shift2               ; no, so round again
  1604.  
  1605.          mov     bp,dx                ; CR shifted, so we're done.
  1606.          inc     bp                   ; point to length counter
  1607.          mov     al,ds:[bp]           ; get it
  1608.          sub     ax,si                ; subtract no. of leading spaces. ah is
  1609.                                       ; zero, so ax is really al.
  1610.          mov     byte ptr ds:[bp],al  ; and replace new byte
  1611.  
  1612. shift_done:
  1613.  
  1614.         pop_all
  1615.         ret
  1616. shift_left        endp
  1617. ;
  1618. restore_buffer    proc 
  1619.         push  bp                      ; restore the buffer from the previous
  1620.         push  ax                      ; use of this function, so that alias
  1621.         mov   bp,dx                   ; commands can be recalled with F3.
  1622.         mov   al,cs:kb_str_len
  1623.         mov   byte ptr ds:[bp+1],al
  1624.         mov   al,cs:kb_str_ch1
  1625.         mov   byte ptr ds:[bp+2],al
  1626.         pop   ax
  1627.         pop   bp
  1628.         ret
  1629. restore_buffer    endp
  1630. ;
  1631. copy_to_psp   proc 
  1632.                                       ; although the command is not an alias
  1633.                                       ; command, don't just iret. Instead,
  1634.                                       ; copy the string to a spare part of
  1635.                                       ; memory, and pretend that that area
  1636.                                       ; of memory contains a valid alias.
  1637.                                       ; That way, the DOS command can have
  1638.                                       ; ampersands in it, which will be 
  1639.                                       ; treated properly.
  1640.                                       ;
  1641.                                       ; The spare part of memory used is the
  1642.                                       ; PSP that remains after installation,
  1643.                                       ; at address CS:5Ch.
  1644.  
  1645.         push_m <es,di,si,bp,cx>
  1646.         cld
  1647.         mov   si,dx
  1648.         add   si,2                    ; from ds:si = ds:dx+2
  1649.         push  cs
  1650.         pop   es
  1651.         mov   di,5ch                  ; to es:di = cs:5ch
  1652.         mov   bp,dx
  1653.         mov   cl,byte ptr ds:[bp+1] 
  1654.         mov   ch,0                    ; copy correct number of bytes
  1655.         rep   movsb
  1656.         mov   byte ptr es:[di],0      ; put null at end
  1657.         pop_m <cx,bp,si,di,es>
  1658.         ;
  1659.         mov   cs:match_pos,5ch
  1660.         mov   cs:multi_start,5ch
  1661.         mov   byte ptr cs:multi_line_outstanding,0
  1662.         ret
  1663. copy_to_psp   endp
  1664. ;
  1665. ab_buffer       proc                    ;Display the DOSEDIT buffer.
  1666.  
  1667.         push_all
  1668.         mov    byte ptr cs:list_count,0 ; count no of lines displayed
  1669.         call   get_lines
  1670.         mov    si,word ptr cs:cmdold    ; get adr of 1st byte of oldest cmd
  1671.         mov    bp,word ptr cs:cmdpnt    ; get adr of 1st byte of current cmd
  1672.         dec    bp                       ; prevent double crlf after listing
  1673.  
  1674. buf_top:
  1675.  
  1676.         mov    bl,byte ptr cs:colour    ; get current ALIAS colour
  1677.         call   crlf
  1678.  
  1679.         inc    byte ptr cs:list_count
  1680.         push   ax
  1681.         mov    ah,byte ptr cs:page_len
  1682.         cmp    byte ptr cs:list_count,ah
  1683.         pop    ax
  1684.         jne    scr_not_full
  1685.         call   list_pause             ; Press Any Key to Continue
  1686.  
  1687. scr_not_full:
  1688.  
  1689.         push_all
  1690.         call   disp_str_colour          ; show string on screen
  1691.         pop_all
  1692.  
  1693. get_again:
  1694.  
  1695.         mov    ah,byte ptr cs:[si]      ; get 1st char of command again
  1696.         cmp    ah,0                     ; end of command?
  1697.         je     new_command              ; yes...
  1698.         call   cmdinc                   ; no, so inc pointer
  1699.         jmp    short get_again          ; and keep looking
  1700.  
  1701. new_command:
  1702.  
  1703.         cmp    si,bp                    ; are all commands printed?
  1704.         je     buf_done
  1705.         call   cmdinc                   ; point to start of next command
  1706.         jmp    short buf_top            ; and start all over again
  1707.  
  1708. buf_done:
  1709.  
  1710.         pop_all
  1711.  
  1712.         disp_ch LF
  1713.         push_m  <di,si,cx,bx,ax>             ; Display a white space.
  1714.         mov     ah,9
  1715.         mov     al,SPACE
  1716.         mov     bl,WHITE               ; attrib
  1717.         call    get_vpage              ; video page into bh
  1718.         mov     cx,1
  1719.         bios_video
  1720.         pop_m   <ax,bx,cx,si,di>
  1721.  
  1722.         ret
  1723. ab_buffer       endp
  1724. ;
  1725. subst   proc
  1726.                                       ; This procedure gets a string which 
  1727.                                       ; starts at cs:match_pos with length
  1728.                                       ; cs:match_len, and puts it in the 
  1729.                                       ; buffer which is set up for a string
  1730.                                       ; by a routine that calls DOS 
  1731.                                       ; function 0Ah.  The string will be 
  1732.                                       ; placed in ram starting at ds:dx+2.
  1733.                                       ; Its length will get put in ds:dx+1
  1734.                                       ; and a carriage return gets put at 
  1735.                                       ; the end of the string, though this 
  1736.                                       ; is not included in the char count.
  1737.  
  1738.  
  1739.         push_all
  1740.         push   cs
  1741.         pop    es                     ; source segment
  1742.         mov    bp,dx                  ; destination segment
  1743.         mov    bl,byte ptr ds:[bp]    ; get length of buffer
  1744.         mov    bh,0                   ; counter
  1745.         add    bp,2                   ; destination offset
  1746.         mov    si,cs:match_pos        ; start of string
  1747.         mov    cl,cs:match_len        ; length
  1748.         cmp    cl,0                   ; is string empty (ie user just pressed
  1749.                                       ; RETURN)
  1750.         jne    keep_on
  1751.         mov    byte ptr ds:[bp],CR    ; put CR at end(!) of empty string
  1752.         jmp    short subst_done
  1753.  
  1754. keep_on:
  1755.  
  1756.         mov    al,es:[si]             ; get char from string
  1757.         mov    byte ptr ds:[bp],al    ; and put it in place
  1758.         dec    cl                     ; count down till whole string copied
  1759.         inc    si                     ; inc source pointer
  1760.         inc    bp                     ; inc dest pointer
  1761.         inc    bh
  1762.         cmp    cl,0                   ; are we done?
  1763.         je     stuffed
  1764.         cmp    bh,bl                  ; or is buffer full?
  1765.         je     stuffed
  1766.         jmp    short keep_on
  1767.  
  1768. stuffed:
  1769.  
  1770.         mov    byte ptr ds:[bp],CR    ; put CR at end
  1771.  
  1772.         push   bp                     ; set length
  1773.         push   ax
  1774.         mov    ah,cs:match_len
  1775.         mov    bp,dx
  1776.         add    bp,1
  1777.         mov    ds:[bp],ah         
  1778.         pop    ax
  1779.         pop    bp
  1780.         pop_all
  1781.  
  1782. subst_done:
  1783.  
  1784.         ret
  1785. subst   endp
  1786. ;
  1787. expand_percents proc
  1788.  
  1789.                                       ; This proc takes the contents of the
  1790.                                       ; buffer at ds:dx, which SUBST has
  1791.                                       ; copied an alias into, and expands any
  1792.                                       ; %n characters into the correct strings
  1793.                                       ; taken from param_buff.
  1794.  
  1795.                                       ; Percent params are handled by Alias in
  1796.                                       ; the same way as DOS batch files,except
  1797.                                       ; that there is no %0 implementation,and
  1798.                                       ; there is a %*, which is the whole
  1799.                                       ; parameter buffer.
  1800.  
  1801.         push_all
  1802.  
  1803. expand_vtop:
  1804.  
  1805.         mov    si,dx                  ; point to start of ds:dx buffer
  1806.         inc    si
  1807.  
  1808. expand_top:
  1809.  
  1810.         inc    si
  1811.         mov    al,byte ptr ds:[si]    ; get char from buffer
  1812.         cmp    al,CR                  ; are we at the end of the buffer?
  1813.         jne    ok
  1814.         jmp    expand_done
  1815. ok:
  1816.         cmp    al,'%'                 ; is the char a percent?
  1817.         je     percent_found          ; jump if so
  1818.         jmp    short expand_top
  1819.  
  1820. percent_found:
  1821.  
  1822.         mov    byte ptr cs:star_flag,0
  1823.  
  1824.                                       ; a percent was found in ds:dx buffer.
  1825.                                       ; It's only valid and expandable if
  1826.                                       ; followed by a digit.
  1827.  
  1828.                                       ; Check si+1, which must be a digit
  1829.                                       ; If we find %*, change it to %1, but
  1830.                                       ; set an internal flag.
  1831.  
  1832.         cmp    byte ptr ds:[si+1],'*'
  1833.         jne    expand12
  1834.         mov    byte ptr ds:[si+1],'1'
  1835.         mov    byte ptr cs:star_flag,1
  1836.  
  1837. expand12:
  1838.  
  1839.         cmp    byte ptr ds:[si+1],'1'
  1840.         jb     expand_top
  1841.         cmp    byte ptr ds:[si+1],'9'
  1842.         ja     expand_top
  1843.  
  1844.  
  1845.                                       ; SI is pointing to a percent char,
  1846.                                       ; which is the start of a valid
  1847.                                       ; parameter sequence.
  1848.  
  1849.         mov    cl,byte ptr ds:[si+1]  ; get the parameter
  1850.         sub    cl,'0'                 ; convert to binary digit
  1851.  
  1852.                                       ; Before we copy parameter in, check
  1853.                                       ; that a) it exists, and b) that it will
  1854.                                       ; fit into the buffer.
  1855.  
  1856.                                       ; Count the number of parameters, to see
  1857.                                       ; if cl exists.
  1858.  
  1859.         push   bp
  1860.         push   bx
  1861.         mov    bp,offset cs:param_buff
  1862.         mov    bh,0
  1863.  
  1864. counter_top:
  1865.  
  1866.         mov    bl,byte ptr cs:[bp]
  1867.         cmp    bl,CR
  1868.         je     counter_done
  1869.         cmp    bl,SPACE
  1870.         je     param_found
  1871.         inc    bp
  1872.         jmp    short counter_top
  1873.  
  1874. param_found:
  1875.  
  1876.         inc    bh
  1877.         inc    bp
  1878.         jmp    short counter_top
  1879.  
  1880. counter_done:
  1881.  
  1882.         cmp    bh,cl                  ; did we find enough parameters?
  1883.         pop    bx
  1884.         pop    bp
  1885.  
  1886.         jae    enough_params
  1887.  
  1888.                                       ; There are not enough params to expand
  1889.                                       ; the % sign currently pointed to by si.
  1890.                                       ; Delete % and the digit.  This is the
  1891.                                       ; way that DOS handles this situation.
  1892.  
  1893.         push   bp
  1894.         mov    bp,si
  1895.         call   close_up_buffer        ; Delete char at bp, and amend length
  1896.         call   close_up_buffer
  1897.         pop    bp
  1898.         dec    si                     ; compensate for expand_top's inc si
  1899.         jmp    short expand_top
  1900.  
  1901.  
  1902. enough_params:
  1903.  
  1904.                                       ; parameter cl exists.  If it will fit,
  1905.                                       ; it can be copied in, but we don't
  1906.                                       ; yet know if it will fit...
  1907.  
  1908.                                       ; find out if parameter cl will fit.
  1909.                                       ; dx = length of buffer, dx+1 holds
  1910.                                       ; current number of chars in buffer.
  1911.                                       ; If length of parameter
  1912.                                       ; <= ([dx]-[dx+1]-1) then all is well.
  1913.  
  1914.                                       ; First, get length of parameter
  1915.         mov    bp,offset cs:param_buff
  1916.         mov    bh,0
  1917.  
  1918. expand5:
  1919.  
  1920.         mov    bl,byte ptr cs:[bp]    ; get char from param_buff
  1921.         cmp    bl,SPACE
  1922.         je     expand4
  1923.         inc    bp
  1924.         jmp    short expand5
  1925.  
  1926. expand4:
  1927.  
  1928.         inc    bp
  1929.         inc    bh
  1930.         cmp    bh,cl
  1931.         jne    expand5
  1932.  
  1933.                                       ; bp contains start of parameter.
  1934.                                       ; Count till next space, or CR, found.
  1935.  
  1936.         mov    bh,0
  1937.         mov    ax,bp                  ; preserve start of parameter
  1938.  
  1939. expand7:
  1940.  
  1941.         mov    bl, byte ptr cs:[bp]
  1942.  
  1943.         cmp    byte ptr cs:star_flag,1
  1944.         je     expand14               ; don't stop at spaces if %*
  1945.  
  1946.         cmp    bl,SPACE
  1947.         je     expand6
  1948.  
  1949. expand14:
  1950.  
  1951.         cmp    bl,CR
  1952.         je     expand6
  1953.         inc    bp
  1954.         inc    bh
  1955.         jmp    short expand7
  1956.  
  1957. expand6:
  1958.  
  1959.                                       ; bh contains length of parameter cl
  1960.  
  1961.         mov    di,dx
  1962.         mov    ch,byte ptr ds:[di]    ; ch = length of buffer,
  1963.         mov    cl,byte ptr ds:[di+1]  ; cl = chars in buffer
  1964.                                       ; Note: This is not the same as
  1965.                                       ; mov cx,word ptr ds:[di], as that would
  1966.                                       ; leave ch and cl transposed.
  1967.  
  1968.         sub    ch,cl
  1969.         dec    ch                     ; ch now contains space left in buffer
  1970.         cmp    bh,ch
  1971.  
  1972.         jna    expand_fits            ; jump if not above.
  1973.                                       ; Can't use jle, cos that's for
  1974.                                       ; signed numbers.
  1975.  
  1976.         call   no_fit                 ; warn user that it doesn't fit.
  1977.         jmp    expand_done            ; parameter will not fit, so quit.
  1978.  
  1979. expand_fits:                          ; parameter will fit so copy it
  1980.  
  1981.  
  1982.                                       ; copy parameter starting at ds:[ax] and
  1983.                                       ; finishing with SPACE or CR into
  1984.                                       ; ds:dx buffer.  Delete the % and the
  1985.                                       ; following 2 chars.  Amend length.
  1986.  
  1987.         mov    di,si
  1988.         mov    si,ax                  ; source is now si, dest is di
  1989.  
  1990.                                       ; First, close up the gap.
  1991.                                       ; Delete char at di, di+1 and di+2,
  1992.                                       ; and amend length.
  1993.  
  1994.         push   bp
  1995.         mov    bp,di
  1996.         call   close_up_buffer        ; delete the %
  1997.         call   close_up_buffer        ; delete the digit
  1998.         pop    bp
  1999.  
  2000.  
  2001.                                       ; now copy in the string
  2002.  
  2003. expand9:
  2004.  
  2005.         mov    al,byte ptr cs:[si]    ; get char
  2006.  
  2007.         cmp    byte ptr cs:star_flag,1
  2008.         je     expand15               ; don't stop at spaces if %*
  2009.  
  2010.         cmp    al,SPACE
  2011.         je     expand11
  2012.  
  2013. expand15:
  2014.  
  2015.         cmp    al,CR
  2016.         je     expand11
  2017.         call   put_in_dsdx            ; insert al into ds:dx buffer at [di].
  2018.                                       ; di returns pointing at new char.
  2019.  
  2020.         inc    si
  2021.         jmp    short expand9
  2022.  
  2023. expand11:
  2024.  
  2025.         jmp    expand_vtop            ; Every time, we start parsing from
  2026.                                       ; dx+2, rather than from where we left
  2027.                                       ; off last time.  This is not the most
  2028.                                       ; efficient coding!
  2029.  
  2030. expand_done:
  2031.  
  2032.         pop_all                       ; Finished proc.  Params substituted.
  2033.  
  2034.         ret
  2035. expand_percents endp
  2036. ;
  2037. close_up_buffer    proc
  2038.  
  2039.  
  2040.                                       ; delete the char at [bp] in a buffer,
  2041.                                       ; whose length is at dx+1. Amend length.
  2042.  
  2043.         push   bp
  2044.         push   ax
  2045.  
  2046.         inc    bp                     ; point past the char to delete
  2047.  
  2048. close1:
  2049.  
  2050.         mov    al,ds:[bp]             ; get a char
  2051.         mov    byte ptr ds:[bp-1], al ; shift the char left
  2052.         cmp    al,CR                  ; are we done
  2053.         je     closed
  2054.         inc    bp
  2055.         jmp    short close1
  2056.  
  2057. closed:
  2058.  
  2059.                                       ; char is deleted.  Amend length.
  2060.  
  2061.         mov    bp,dx
  2062.         inc    bp                     ; point to length
  2063.         mov    al,byte ptr ds:[bp]    ; get length
  2064.         dec    al                     ; decrement it
  2065.         mov    byte ptr ds:[bp],al    ; and write new value back
  2066.         pop    ax
  2067.         pop    bp
  2068.         ret
  2069. close_up_buffer endp
  2070. ;
  2071. put_in_dsdx proc                      ; insert al into ds:dx buffer at ds:[di]
  2072.                                       ; di returns pointing at new char
  2073.                                       ; Update length at dx+1
  2074.         push   si
  2075.         push   ax
  2076.         push   bx
  2077.  
  2078.         mov    si,dx                  ; point to start of buffer
  2079.         inc    si                     ; point to length
  2080.         mov    bl,byte ptr ds:[si]    ; get length
  2081.  
  2082.         inc    bl
  2083.         mov    byte ptr ds:[si],bl    ; update length while we're here
  2084.         dec    bl
  2085.  
  2086.         mov    bh,0
  2087.         add    si,bx                  ; point to terminating CR
  2088.         inc    si
  2089.         inc    si
  2090.  
  2091. put_in:
  2092.  
  2093.         dec    si
  2094.         mov    ah,byte ptr ds:[si]    ; get char from string
  2095.         mov    byte ptr ds:[si+1],ah  ; shift it right
  2096.         cmp    si,di                  ; are we done?
  2097.         jne    put_in
  2098.         mov    byte ptr ds:[di],al    ; insert char in newly created space
  2099.         inc    di
  2100.  
  2101.         pop    bx
  2102.         pop    ax
  2103.         pop    si
  2104.  
  2105.         ret
  2106.  
  2107. put_in_dsdx endp
  2108. ;
  2109. no_fit  proc                          ; The string can't be expanded, cos it
  2110.                                       ; will end up longer than the ds:dx
  2111.                                       ; buffer provided for it.  Clear the
  2112.                                       ; buffer and display a warning message.
  2113.         mov    bp,dx
  2114.         mov    byte ptr ds:[bp+1],0   ; set length to 0
  2115.         mov    byte ptr ds:[bp+2],CR  ; add a CR on end
  2116.         mov    bl,cs:colour
  2117.         mov    si,offset cs:no_fit_msg
  2118.         call   disp_str_colour
  2119.         ret
  2120. no_fit  endp
  2121. ;
  2122. echo    proc
  2123.                                       ; This routine is called once the
  2124.                                       ; aliased string has been assembled
  2125.                                       ; at ds:dx+2, and immediately before
  2126.                                       ; the IRET.  If echo is turned on,
  2127.                                       ; we echo the string at ds:dx+2 to the
  2128.                                       ; console, in the current colour, and
  2129.                                       ; enclosed in square brackets.
  2130.                                       ; This echo only occurs if the string
  2131.                                       ; was placed at ds:dx+2 because an alias
  2132.                                       ; was found in the table.  If no 
  2133.                                       ; substitution ocurred, there's no echo.
  2134.  
  2135.  
  2136.         cmp   byte ptr cs:echo_status,1   ; do we want echo?
  2137.         je    echo_wanted
  2138.         jmp   not_required
  2139.  
  2140. echo_wanted:
  2141.  
  2142.         call  crlf    
  2143.         push_all
  2144.         mov   si,offset cs:left_sq_br ; display a '[' in current colour
  2145.         mov   bl,cs:colour
  2146.         call  disp_str_colour
  2147.         pop_all
  2148.  
  2149.  
  2150.         push_all
  2151.         mov   si,dx                   ; start of string
  2152.         add   si,2
  2153.         mov   bl,cs:colour            ; screen attribute to use
  2154.  
  2155.         mov   bp,dx
  2156.         mov   al,ds:[bp+1]            ; get length of string
  2157.         mov   ah,0
  2158.         add   bp,ax                   ; point to CR at end of string
  2159.         add   bp,2                    ; skip first 2 bytes
  2160.         mov   byte ptr ds:[bp],0      ; change CR to a 0 for use with proc
  2161.  
  2162.         push_all
  2163.         mov   byte ptr cs:echo_flag,1 ; 'cos string is in ds
  2164.         call  disp_str_colour         ; display 0-terminated string
  2165.         mov   byte ptr cs:echo_flag,0 ; back to cs for other procs to use
  2166.         pop_all
  2167.  
  2168.         mov   byte ptr ds:[bp],CR     ; put the CR back
  2169.         pop_all
  2170.  
  2171.         push_all
  2172.         mov   si,offset cs:rght_sq_br ; display a ']' in current colour
  2173.         mov   bl,cs:colour
  2174.         call  disp_str_colour
  2175.         pop_all
  2176.         disp_ch LF                   ; ensure DOS default colour returns to
  2177.                                      ; white.
  2178.  
  2179. not_required:
  2180.         ret
  2181. echo    endp
  2182. ;
  2183. ab_none proc                          ; ALIAS N turns off aliases
  2184.         mov   byte ptr cs:ab_status,0
  2185.         call  crlf
  2186.         ret
  2187. ab_none endp
  2188. ab_info proc                          ; ALIAS I displays info
  2189.         push_m <dx,ds,ax>             ; Display version number
  2190.         mov   ax,cs
  2191.         mov   ds,ax
  2192.         push_m <bx,si>
  2193.         mov   si,offset cs:version
  2194.         mov   bl,cs:colour 
  2195.         call  disp_str_colour
  2196.         pop_m <si,bx>
  2197.         pop_m <ax,ds,dx>
  2198.         ; 
  2199.         push_all
  2200.         cmp   byte ptr cs:ab_status,0 ; don't display show/hide if off
  2201.         je    info2
  2202.         cmp   byte ptr cs:echo_status,0 ; display show or hide
  2203.         je    info1
  2204.         mov   si,offset cs:msg_show
  2205.         mov   bl,byte ptr cs:colour
  2206.         call  disp_str_colour
  2207.         jmp   info2
  2208.  
  2209. info1:
  2210.  
  2211.         mov   si,offset cs:msg_hide
  2212.         mov   bl,byte ptr cs:colour
  2213.         call  disp_str_colour
  2214.  
  2215. info2:                                ; display on/off/global
  2216.  
  2217.         cmp   byte ptr cs:ab_status,0
  2218.         je    info3
  2219.         cmp   byte ptr cs:expand_from,0
  2220.         je    info4
  2221.         mov   si,offset cs:msg_global
  2222.         mov   bl,byte ptr cs:colour
  2223.         call  disp_str_colour
  2224.         jmp   info6
  2225.  
  2226. info4:
  2227.  
  2228.         mov   si,offset cs:msg_prompt
  2229.         mov   bl,byte ptr cs:colour
  2230.         call  disp_str_colour
  2231.         jmp   info6
  2232.  
  2233. info3:
  2234.  
  2235.         mov   si,offset cs:msg_off
  2236.         mov   bl,byte ptr cs:colour
  2237.         call  disp_str_colour
  2238.  
  2239. info6:
  2240.  
  2241.         pop_all
  2242.         call  disp_def_fn               ; display full path of default file
  2243.         call  alias_count               ; display no of aliases, + table size
  2244.  
  2245.         push_m  <si,di,cx,bx,ax>             ; Display a white space.
  2246.         mov     ah,9
  2247.         mov     al,SPACE
  2248.         mov     bl,WHITE               ; attrib
  2249.         call    get_vpage              ; video page into bh
  2250.         mov     cx,1
  2251.         bios_video
  2252.         pop_m   <ax,bx,cx,di,si>
  2253.  
  2254.         ret  
  2255. ab_info endp
  2256. disp_def_fn   proc                      ; Display the default file name that
  2257.                                         ; will be used in ALIAS W commands.
  2258.                                         ; If the def_dir string is empty,
  2259.                                         ; display default_fn.  If def_dir is
  2260.                                         ; not empty, it is the path and file
  2261.                                         ; that was loaded at install time, so
  2262.                                         ; it's the one to display.
  2263.  
  2264.         push_all
  2265.         mov   si,offset cs:def_fn_msg
  2266.         mov   bl,byte ptr cs:colour
  2267.         call  disp_str_colour
  2268.  
  2269.         mov   si,offset cs:default_fn   ; use the non-pathed file?
  2270.         mov   al,byte ptr cs:[def_dir]  ; get 1st byte of pathed string
  2271.         cmp   al,0                      ; is it empty?
  2272.         je    use_non                   ; yes, so stay as we are
  2273.         mov   si,offset cs:defdir_hdr   ; pathed string exists so use instead.
  2274.  
  2275. use_non:
  2276.  
  2277.         mov   bl,byte ptr cs:colour
  2278.         call  disp_str_colour
  2279.         pop_all
  2280.         ret
  2281. disp_def_fn   endp
  2282. ;
  2283. alias_count   proc                      ; Called by ALIAS I command to display
  2284.                                         ; the number of defined/undefined
  2285.                                         ; aliases.
  2286.  
  2287.         call  count_aliases             ; count entries in table and plug the
  2288.                                         ; numbers into the string about to be
  2289.                                         ; displayed.
  2290.         push_all
  2291.         mov   si,offset cs:count_msg    ; display the message
  2292.         mov   bl, byte ptr cs:colour
  2293.         call  disp_str_colour
  2294.         pop_all
  2295.         ret
  2296. alias_count   endp
  2297. ;
  2298. count_aliases  proc
  2299.  
  2300.         push_m <ax,bx,cx,dx,bp>
  2301.         mov    ax,0                     ; count full entries in ax
  2302.         mov    bx,0                     ; count total table entries in bx
  2303.         mov    bp,offset cs:ab_table    ; start of the table
  2304.  
  2305. count_top:
  2306.  
  2307.         mov    dh,byte ptr cs:[bp]      ; get 1st char from table entry
  2308.         cmp    dh,0F0h
  2309.         je     count_done
  2310.         cmp    dh,0                     ; is entry full?
  2311.         je     count_empty              ; no, then it's empty!
  2312.         inc    ax                       ; full entries
  2313.  
  2314. count_empty:
  2315.  
  2316.         inc    bx                       ; total entries
  2317.         add    bp,RHS_LEN + LHS_LEN + 1 ; point to next entry
  2318.         jmp    short count_top
  2319.  
  2320. count_done:
  2321.  
  2322.                                         ; ax and bx contain totals. Now plug
  2323.                                         ; them in.
  2324.         aam                             ; put digits of ax into ah and al
  2325.         add    ax,3030h                 ; convert to ascii
  2326.         mov    bp,offset cs:count_msg1
  2327.         mov    byte ptr cs:[bp],ah
  2328.         mov    byte ptr cs:[bp+1],al
  2329.  
  2330.         mov    ax,bx                    ; Now do the second number
  2331.         aam
  2332.         add    ax,3030h
  2333.         mov    bp,offset cs:count_msg2
  2334.         mov    byte ptr cs:[bp],ah
  2335.         mov    byte ptr cs:[bp+1],al
  2336.  
  2337.         pop_m  <bp,dx,cx,bx,ax>
  2338.         ret
  2339. count_aliases  endp
  2340. ;
  2341. ab_prompt     proc
  2342.         mov   byte ptr cs:expand_from,0 ; expand from dos prompt
  2343.         mov   byte ptr cs:ab_status,1   ; turn on
  2344.         call  crlf
  2345.         ret
  2346. ab_prompt     endp
  2347. ;
  2348. ab_global     proc
  2349.         mov   byte ptr cs:expand_from,1 ; expand globally
  2350.         mov   byte ptr cs:ab_status,1   ; turn on
  2351.         call  crlf
  2352.         ret
  2353. ab_global     endp
  2354. ;
  2355. ab_help proc                          ; ALIAS ? gives help
  2356.         push_m <bx,si,dx,ds,ax>
  2357.         mov   bl,cs:colour 
  2358.         mov   si,offset cs:help_text
  2359.         call  disp_str_colour
  2360.         pop_m <ax,ds,dx,si,bx>
  2361.         ret
  2362. ab_help endp
  2363. ab_add  proc                          ; ALIAS A <arg> <string>
  2364.  
  2365.                                       ; Before doing anything else,check that
  2366.                                       ; user left a space between ALIAS A and
  2367.                                       ; the arg, or prog will hang.  ie, 
  2368.                                       ; abort if [dx+9] is not a space.
  2369.  
  2370.         push_m <ax,bp>
  2371.         mov   bp,dx
  2372.         mov   ah,byte ptr ds:[bp+9]   ; get the char between ALIAS L and arg
  2373.         cmp   ah,' '                  ; is it a space
  2374.         pop_m <bp,ax>
  2375.         je    ok_space3               ; continue if ok. Can't write jne 'cos
  2376.                                       ; out of range.
  2377.         call  syntax_error            ; error - no action taken
  2378.         jmp   add_err                 ; if not a space, abort A command
  2379.  
  2380. ok_space3:
  2381.  
  2382.         call  to_lower                ; Make the LHS part of the alias lower
  2383.                                       ; case.  Leave the RHS part as it is,
  2384.                                       ; because user may want to specify
  2385.                                       ; a case-specific alias, for example
  2386.                                       ; as command-line options on MS C.
  2387.  
  2388.         push_m <ax,bx,cx,dx,bp,si>
  2389.         mov   si,0                    ; count length of arg
  2390.         mov   bp,dx
  2391.         add   bp,10                   ; point to arg
  2392.  
  2393. add2:
  2394.  
  2395.         mov   ah,ds:[bp+si]           ; get arg character
  2396.                                       ; is it c/r?  If so, no string was
  2397.                                       ; typed so abort
  2398.         cmp   ah,CR 
  2399.         jne   not_cr
  2400.         pop_m <si,bp,dx,cx,bx,ax>
  2401.         call  syntax_error
  2402.         jmp   add_err                 ; abort
  2403.      
  2404. not_cr:
  2405.  
  2406.         cmp   ah,' '                  ; is it a space?
  2407.         je    add1
  2408.         cmp   si,LHS_LEN              ; or have we done 6 chars?
  2409.         je    add1    
  2410.         inc   si                      ; no. point to next char
  2411.         jmp   add2
  2412.  
  2413. add1:
  2414.  
  2415.         mov   bx,si
  2416.         mov   cs:arg_end,bl           ; arg_end is length of arg
  2417.         ; 
  2418.         mov   si,0
  2419.         mov   bp,dx
  2420.  
  2421.         add   bp,10                   ; point to 1st char of lhs
  2422.         mov   al,cs:arg_end
  2423.         mov   ah,0
  2424.         add   bp,ax
  2425.                                       ; bp should now point to a space, and
  2426.                                       ; incrementing it will point to the
  2427.                                       ; start of the rhs.  But this will not
  2428.                                       ; be so if the lhs was > 6 chars, so
  2429.                                       ; so we may need to add more to bp.
  2430.  
  2431. add11:
  2432.  
  2433.         cmp   byte ptr ds:[bp],SPACE  ; are we ok?
  2434.         je    add10                   ; yes, so point to rhs and we're ok
  2435.         inc   bp
  2436.         jmp   short add11
  2437.  
  2438. add10:
  2439.  
  2440.         inc   bp
  2441.  
  2442. add3:    
  2443.  
  2444.         mov   ah,ds:[bp+si]            
  2445.         cmp   ah,CR                   ; end of string
  2446.         je    add4
  2447.         cmp   si,RHS_LEN              ; truncate if necessary
  2448.         je    add4
  2449.         inc   si
  2450.         jmp   add3
  2451.  
  2452. add4:
  2453.  
  2454.         mov   bx,si
  2455.         mov   cs:str_end,bl
  2456.                                       ; Arg starts at dx+10, length arg_end. 
  2457.                                       ; Str starts at dx+11+arg_end, 
  2458.                                       ; with length str_end
  2459.         pop_m <si,bp,dx,cx,bx,ax>
  2460.         ; 
  2461.         cmp   byte ptr cs:arg_end,LHS_LEN
  2462.         jbe   add6                    ; must be < 6 chars
  2463.         jmp   add_err                 ; else give error and exit.
  2464.                                       ; Actually, string has been truncated
  2465.                                       ; above, so it should never fail here.
  2466.  
  2467. add6:
  2468.  
  2469.         cmp   byte ptr cs:str_end,RHS_LEN ; Ensure length of rhs string is OK.
  2470.                                           ; It should be, cos it was truncated
  2471.                                           ; by the routines above.
  2472.         jbe   add7
  2473.         jmp   add_err
  2474.  
  2475. add7:
  2476.  
  2477.         push_m <es,di,cx,ax>          ; fill 6-char buffer with 0's
  2478.         cld
  2479.         mov   ax,cs
  2480.         mov   es,ax
  2481.         mov   al,0
  2482.         mov   di,offset cs:buffer2
  2483.         mov   cx,LHS_LEN
  2484.         rep   stosb
  2485.         pop_m <ax,cx,di,es>
  2486.  
  2487.                                       ; Put arg into buffer.
  2488.  
  2489.         push_m <ax,cx,dx,es,ds,di,si>
  2490.         cld
  2491.         mov   ax,cs
  2492.         mov   si,dx
  2493.         add   si,10                   ; copy from ds:dx+10
  2494.         mov   es,ax
  2495.         mov   di,offset cs:buffer2    ; copy to buffer
  2496.         mov   cl,cs:arg_end           ; no of bytes to copy
  2497.         mov   ch,0
  2498.         rep   movsb
  2499.         pop_m <si,di,ds,es,dx,cx,ax>
  2500.         ; 
  2501.                                       ; Now scan buffer vs table,
  2502.                                       ; to ensure that
  2503.                                       ; arg doesn't already exist
  2504.         push_m <ax,bx,cx,ds,es,di,si>
  2505.         mov   bh,1                    ; count for up to 30 comparisons
  2506.         mov   di,offset cs:ab_table
  2507.  
  2508. scan:
  2509.  
  2510.         mov   ax,cs
  2511.         mov   es,ax
  2512.         mov   ds,ax
  2513.         mov   si,offset cs:buffer2
  2514.         mov   cx,LHS_LEN
  2515.         cld
  2516.         repe  cmpsb
  2517.         jne   scan2
  2518.         jmp   already_in_table
  2519.  
  2520. scan2:                                ; no match, so loop again
  2521.  
  2522.         inc   bh
  2523.         cmp   bh,TBL_LEN + 1
  2524.         je    not_in_table
  2525.         add   di,RHS_LEN + 1
  2526.         add   di,cx
  2527.         jmp   scan
  2528.  
  2529. already_in_table:                     ; can't add, cos it already exists
  2530.  
  2531.         pop_m <si,di,es,ds,cx,bx,ax>
  2532.         call  exist_err                 ; display error msg
  2533.         ret
  2534.  
  2535. not_in_table:
  2536.  
  2537.         pop_m <si,di,es,ds,cx,bx,ax>
  2538.                                       ; we have a string that does not
  2539.                                       ; already exist. Now find an empty
  2540.                                       ; table entry
  2541.         push_m <ax,bx,bp>
  2542.         mov   bh,1                    ; do up to 30 comparisons
  2543.         mov   bp,offset cs:ab_table   ; start of table
  2544.  
  2545. keep_looking:
  2546.  
  2547.         mov   ah,cs:[bp]              ; get 1st char of arg
  2548.         cmp   ah,0                    ; if char is 0 then space is free
  2549.         je    entry_spare          
  2550.         add   bh,1                    ; inc counter
  2551.         add   bp,LHS_LEN+RHS_LEN+1
  2552.         cmp   bh,TBL_LEN + 1          ; all done?
  2553.         jne   keep_looking            ; no , so round again
  2554.         pop_m <bp,bx,ax>              ; no space, so quit
  2555.         call  table_full              ; and display error message
  2556.         ret
  2557.  
  2558. entry_spare:
  2559.  
  2560.         mov   cs:spare,bp             ; 1st byte of table entry
  2561.         pop_m <bp,bx,ax>
  2562.         ; 
  2563.                                       ; fill table from spare for 77
  2564.                                       ; bytes, with 0
  2565.         push_m <di,es,cx,ax>
  2566.         cld
  2567.         mov   ax,cs
  2568.         mov   es,ax             
  2569.         mov   di,cs:spare
  2570.         mov   cx,LHS_LEN + RHS_LEN + 1
  2571.         mov   al,0
  2572.         rep   stosb
  2573.         pop_m <ax,cx,es,di>
  2574.         ; 
  2575.         push_m <ax,cx,di,si,es>
  2576.  
  2577.         mov   ax,dx
  2578.         add   ax,10
  2579.         mov   si,ax                   ; copy arg from ds:di
  2580.         mov   ax,cs
  2581.         mov   es,ax                   ; to es:di
  2582.         mov   di,cs:spare
  2583.         mov   ch,0
  2584.         mov   cl,cs:arg_end
  2585.         rep   movsb
  2586.         ; 
  2587.         mov   ax,dx
  2588.         add   ax,10
  2589.         mov   bh,0
  2590.         mov   bl,cs:arg_end
  2591.         add   ax,bx
  2592.         mov   si,ax                   ; copy string from ds:si.
  2593.                                       ; SI currently points to the space
  2594.                                       ; before the rhs in the user's string.
  2595.                                       ; However, if the user entered an lhs
  2596.                                       ; that was too long we need to skip over
  2597.                                       ; those extra chars that are here.
  2598.  
  2599. add14:
  2600.  
  2601.         cmp   byte ptr ds:[si],SPACE  ; are we in the right place
  2602.         je    add12                   ; yes, then carry on
  2603.         inc   si                      ; else point to next char and try again
  2604.         jmp   short add14
  2605.  
  2606. add12:
  2607.  
  2608.         inc   si
  2609.         mov   ax,cs
  2610.         mov   es,ax                   ; to es:di
  2611.         mov   di,cs:spare
  2612.         add   di,LHS_LEN              ; copy to string, not arg
  2613.         mov   ch,0
  2614.         mov   cl,cs:str_end           ; no of chars to copy
  2615.         rep   movsb
  2616.         ; 
  2617.         pop_m <es,si,di,cx,ax>
  2618.  
  2619. add5:
  2620.  
  2621.         call  crlf
  2622.  
  2623. add_err:
  2624.  
  2625.         ret
  2626. ab_add  endp
  2627.         ; 
  2628. table_full    proc                    ; display 'table full' msg
  2629.         push_all
  2630.         mov   bl,cs:colour
  2631.         mov   si,offset cs:table_full_msg
  2632.         call  disp_str_colour
  2633.         pop_all
  2634.         ret
  2635. table_full    endp
  2636. ;
  2637. ab_colour proc
  2638.         call  crlf
  2639.         push_all
  2640.  
  2641.         mov   bl,cs:colour
  2642.         mov   byte ptr cs:old_col,bl  ; save current colour in case of ESC
  2643.  
  2644. colour_top:
  2645.  
  2646.         mov   bl,cs:colour            ; get current colour
  2647.         mov   si,offset cs:colour_msg
  2648.         call  disp_str_colour
  2649.  
  2650. get_colour_key:
  2651.  
  2652.         mov   ah,8                    ; get key. no echo
  2653.         int   21h
  2654.         cmp   al,0                    ; 2-byte code?
  2655.         je    get_colour_key          ; loop again if yes
  2656.         ;
  2657.         cmp   al,32                   ; space character?
  2658.         jne   colour1
  2659.         cmp   byte ptr cs:colour,15   ; if colour = 15, reset to 1
  2660.         jne   colour2
  2661.         mov   byte ptr cs:colour,1
  2662.         jmp   colour_top
  2663.  
  2664. colour2:
  2665.  
  2666.         inc   byte ptr cs:colour
  2667.         jmp   colour_top
  2668.  
  2669. colour1:                              ; not a space. try for cr
  2670.  
  2671.         cmp   al,13
  2672.         je    colour3                 ; jmp if cr.
  2673.         cmp   al,27                   ; ESC?
  2674.         jne   get_colour_key          ; get char again if not.
  2675.        
  2676.         mov   bl,cs:old_col           ; ESC, so get old colour
  2677.         mov   byte ptr cs:colour,bl   ; and make it the current colour
  2678.  
  2679. colour3:
  2680.  
  2681.         pop_all 
  2682.         disp_ch CR                    ; all done. move crsr to start of line
  2683.         push_all
  2684.         mov   al,32                   ; display a line of spaces over line
  2685.         mov   bl,WHITE
  2686.         mov   bh,0
  2687.         mov   cx,75
  2688.         mov   ah,9
  2689.         bios_video
  2690.         pop_all 
  2691.         disp_ch CR                    ; put crsr at start of line again
  2692.         ret
  2693. ab_colour     endp
  2694. ;
  2695. ab_show proc
  2696.         mov   byte ptr cs:echo_status,1
  2697.         call  crlf
  2698.         ret
  2699. ab_show endp
  2700. ;
  2701. ab_hide proc
  2702.         mov   byte ptr cs:echo_status,0
  2703.         call  crlf
  2704.         ret
  2705. ab_hide endp
  2706. ;
  2707. ab_delete     proc                    ; ALIAS D <arg> deletes an entry
  2708.         push_m <ax,bx,cx,dx,es,ds,si,di,bp>
  2709.         mov   bp,dx
  2710.         mov   ah,byte ptr ds:[bp+1]   ; get length of string
  2711.  
  2712.         cmp   ah,7                    ; if just ALIAS D typed...
  2713.         je    not_there               ; ...then do nothing
  2714.  
  2715.                                       ; Before doing anything else,check that
  2716.                                       ; user left a space between ALIAS D and
  2717.                                       ; the arg, or prog will hang.  ie, 
  2718.                                       ; abort if [dx+9] is not a space.
  2719.  
  2720.         push_m <ax,bp>
  2721.         mov   bp,dx
  2722.         mov   ah,byte ptr ds:[bp+9]   ; get the char between ALIAS D and arg
  2723.         cmp   ah,' '                  ; is it a space
  2724.         pop_m <bp,ax>
  2725.         je    ok_space2               ; continue if ok. Can't write jne 'cos
  2726.                                       ; out of range.
  2727.         jmp   not_there               ; if not a space, abort D command
  2728.  
  2729. ok_space2:
  2730.  
  2731.         sub   ah,8                    ; arg is at dx+10 with len arg_end
  2732.         mov   cs:arg_end,ah                                       
  2733.                                       ; fill buffer with 0's
  2734.         mov   ax,cs
  2735.         mov   es,ax
  2736.         mov   al,0
  2737.         mov   di,offset cs:buffer2
  2738.         mov   cx,LHS_LEN
  2739.         cld
  2740.         rep   stosb
  2741.   
  2742.         call  copy_to_buffer2         ; copy arg into buffer
  2743.  
  2744.                                       ; now look through table. If arg
  2745.                                       ; exists, delete it.
  2746.  
  2747.         mov   bh,1                    ; do up to 30 comparisons
  2748.         mov   di,offset cs:ab_table
  2749.            
  2750. not_there_yet:
  2751.  
  2752.         mov   ax,cs
  2753.         mov   es,ax
  2754.         mov   ds,ax
  2755.         mov   si,offset cs:buffer2
  2756.         mov   cx,LHS_LEN
  2757.         cld
  2758.         repe  cmpsb
  2759.         jne   still_not_there
  2760.         jmp   got_it
  2761.  
  2762. still_not_there:
  2763.  
  2764.         inc   bh
  2765.         cmp   bh,TBL_LEN + 1
  2766.         je    not_there
  2767.         add   di,RHS_LEN + 1
  2768.         add   di,cx
  2769.         jmp   not_there_yet
  2770.  
  2771. got_it:                               ; di holds start of table
  2772.                                       ; entry so delete it
  2773.         sub   di,LHS_LEN
  2774.         mov   byte ptr es:[di],0      ; set 1st char to 0, = deleted
  2775.         pop_m <bp,di,si,ds,es,dx,cx,bx,ax>
  2776.         call  crlf
  2777.         ret
  2778.  
  2779. not_there:
  2780.  
  2781.         pop_m <bp,di,si,ds,es,dx,cx,bx,ax>
  2782.         call  not_found               ; show error cos entry doesn't exist
  2783.         ret
  2784. ab_delete     endp
  2785. ab_flush      proc                    ; ALIAS F wipes entire table.
  2786.         call  are_you_sure            ; ask user to confirm
  2787.         cmp   byte ptr cs:confirm,1   ; is user sure?
  2788.         jne   flush_done              ; jump if no
  2789.         push_m <di,es,cx,ax>
  2790.         mov   ax,cs
  2791.         mov   es,ax
  2792.         mov   di,offset cs:ab_table
  2793.         mov   al,0
  2794.         mov   cx,(RHS_LEN + LHS_LEN + 1) * TBL_LEN
  2795.         rep   stosb                   ; Fill entire table with 0's.  Don't
  2796.         pop_m <ax,cx,es,di>           ; erase the bytes before the actual
  2797.                                       ; data, as these hold other bits of
  2798.                                       ; info that get saved with the table.
  2799. flush_done:
  2800.         ret
  2801. ab_flush      endp
  2802. ab_list proc                          ; ALIAS L lists the whole table.
  2803.                                       ; ALIAS L <arg> lists specified entry
  2804.                                       ; Note: the search routines used here
  2805.                                       ; are direct copies of the ones from
  2806.                                       ; the D command.  Should really be put
  2807.                                       ; into a proc to save space.
  2808.  
  2809. call get_lines                        ; Set byte at cs:page_len to no. of
  2810.                                       ; lines that screen can display.
  2811.  
  2812.         push_m <bp,ax>
  2813.         mov   bp,dx
  2814.         mov   ah,byte ptr ds:[bp+1]   ; get length of string into ah
  2815.         cmp   ah,7                    ; just ALIAS L typed?
  2816.         pop_m  <ax,bp>
  2817.         jne   list_single             ; if not, list a single entry
  2818.         jmp list_all                  ; If just ALIAS L, goto list_all
  2819.  
  2820. list_single:
  2821.                                       ; search table for specified entry..
  2822.                                       ; and list it if it exists.
  2823.  
  2824.                                       ; Before doing anything else,check that
  2825.                                       ; user left a space between ALIAS L and
  2826.                                       ; the arg, or prog will hang.  ie, 
  2827.                                       ; abort if [dx+9] is not a space.
  2828.  
  2829.         push_m <ax,bp>
  2830.         mov   bp,dx
  2831.         mov   ah,byte ptr ds:[bp+9]   ; get the char between ALIAS L and arg
  2832.         cmp   ah,' '                  ; is it a space
  2833.         pop_m <bp,ax>
  2834.         je    ok_space                ; continue if ok. Can't write jne 'cos
  2835.                                       ; out of range.
  2836.         call  syntax_error
  2837.         jmp   list4                   ; if not a space, abort L command
  2838.  
  2839. ok_space:
  2840.  
  2841.         push_m <ax,bx,cx,dx,es,ds,si,di,bp>
  2842.         mov   bp,dx
  2843.         mov   ah,byte ptr ds:[bp+1]   ; get length of string into ah
  2844.         sub   ah,8
  2845.         mov   cs:arg_end,ah           ; the arg specified in cmd line is 
  2846.                                       ; at dx+10, with length arg_end
  2847.  
  2848.                                       ; fill buffer with 0's
  2849.         mov   ax,cs
  2850.         mov   es,ax
  2851.         mov   al,0
  2852.         mov   di,offset cs:buffer2
  2853.         mov   cx,LHS_LEN
  2854.         cld
  2855.         rep   stosb
  2856.  
  2857.         call  copy_to_buffer2         ; copy string to buffer
  2858.  
  2859.                                       ; now look through table. If arg
  2860.                                       ; exists, list it.
  2861.  
  2862.         mov   bh,1                    ; do up to 30 comparisons
  2863.         mov   di,offset cs:ab_table 
  2864.            
  2865. list_not_there_yet:
  2866.  
  2867.         mov   ax,cs
  2868.         mov   es,ax
  2869.         mov   ds,ax
  2870.         mov   si,offset cs:buffer2
  2871.         mov   cx,LHS_LEN
  2872.         cld
  2873.         repe  cmpsb
  2874.         jne   list_still_not_there
  2875.         jmp   list_got_it
  2876.  
  2877. list_still_not_there:
  2878.  
  2879.         inc   bh
  2880.         cmp   bh,TBL_LEN + 1
  2881.         je    list_not_there
  2882.         add   di,RHS_LEN + 1
  2883.         add   di,cx
  2884.         jmp   list_not_there_yet
  2885.  
  2886. list_got_it:                          ; di holds start of table entry.
  2887.  
  2888.         sub   di,LHS_LEN              ; move to start of entry
  2889.         call  crlf                    ; move crsr below DOS prompt line
  2890.         call  crlf                    ; and go down a line
  2891.         call  list_an_entry           ; list it in current colour
  2892.         pop_m <bp,di,si,ds,es,dx,cx,bx,ax>
  2893.         jmp   list4
  2894.  
  2895. list_not_there:
  2896.  
  2897.         pop_m <bp,di,si,ds,es,dx,cx,bx,ax>
  2898.         call  not_found               ; display error message
  2899.         jmp   list4                   ; end of selective list routine
  2900.  
  2901. list_all:                             ; list whole table
  2902.  
  2903.         mov   byte ptr cs:list_count,0 ; line counter
  2904.         push_m <di,ds,dx,cx,bx,ax>
  2905.         call  crlf
  2906.         call  crlf
  2907.         mov   bh,1                    ; count 30 loops through table
  2908.         mov   di,offset cs:ab_table   ; point to start of table
  2909.  
  2910. list1:
  2911.  
  2912.         mov   ah,cs:[di]              ; get 1st char of arg
  2913.         cmp   ah,0                    ; is entry empty?
  2914.         jne   not_empty
  2915.         jmp   list2                   ; jump if so
  2916.  
  2917. not_empty:
  2918.  
  2919.         inc    byte ptr cs:list_count
  2920.         push   ax
  2921.         mov    ah,byte ptr cs:page_len
  2922.         cmp    byte ptr cs:list_count,ah
  2923.         pop    ax
  2924.         jne    page_not_full
  2925.         call   list_pause             ; Press Any Key to Continue
  2926.  
  2927. page_not_full:
  2928.  
  2929.         call   list_an_entry          ; list current entry in current colour
  2930. list2:                                ; ..unless current table entry is empty
  2931.         inc   bh                      ; counter for no of entries
  2932.         cmp   bh,TBL_LEN + 1          ; have we seen all the table
  2933.         je    list3                   ; all done if yes
  2934.         add   di,LHS_LEN + RHS_LEN + 1 ; else point to next entry
  2935.         jmp   list1                   ; and do it all again
  2936.  
  2937. list3:     
  2938.  
  2939.         pop_m <ax,bx,cx,dx,ds,di>
  2940. list4:
  2941.  
  2942.                                       ; Write a white space, for BIOS func 0Eh
  2943.                                       ; to use as reference for new attrib.
  2944.         call    crlf
  2945.         push_m  <cx,bx,ax,di,si>
  2946.         mov     ah,9
  2947.         mov     al,SPACE
  2948.         mov     bl,WHITE               ; attrib
  2949.         call    get_vpage              ; video page into bh
  2950.         mov     cx,1
  2951.         bios_video
  2952.         pop_m   <si,di,ax,bx,cx>
  2953.  
  2954.         ret
  2955. ab_list endp
  2956. ;
  2957. not_found proc                        ; Display error message if the subject
  2958.                                       ; of an ALIAS L <arg> is not found.
  2959.         push_all
  2960.         mov    bl,byte ptr cs:colour
  2961.         mov    si,offset cs:err_nfound
  2962.         call   disp_str_colour
  2963.         pop_all
  2964.         ret
  2965. not_found endp
  2966. ;
  2967. exist_err proc                        ; Display error message if the subject
  2968.                                     ; of an ALIAS A already exists.
  2969.         push_all
  2970.         mov    bl,byte ptr cs:colour
  2971.         mov    si,offset cs:exist_msg
  2972.         call   disp_str_colour
  2973.         pop_all
  2974.         ret
  2975. exist_err endp
  2976. ;
  2977. get_lines proc
  2978.  
  2979.         push  ax                      ; Set page_len to no. of lines on scrn,
  2980.         push  ds                      ; so listings can pause when necessary.
  2981.         mov   ax,40h
  2982.         mov   ds,ax
  2983.         mov   ah,byte ptr ds:[84h]    ; get DOS's screen length (in lines)
  2984.         pop   ds
  2985.         cmp   ah,0
  2986.         je    not_really_0
  2987.         jmp   short length_set
  2988.  
  2989. not_really_0:
  2990.  
  2991.         mov   byte ptr cs:page_len,25  ; If byte is 0, length is 25.  That's
  2992.         jmp   short length_set_2       ; the rule, according to DOS books.
  2993.  
  2994. length_set:
  2995.  
  2996.         mov   byte ptr cs:page_len,ah
  2997.  
  2998. length_set_2:
  2999.  
  3000.         pop   ax                      ; page_length is now set.
  3001.         ret
  3002. get_lines endp
  3003. ;
  3004. list_pause    proc
  3005.                                       ; Display a Press Any Key to Cont msg
  3006.         push_all
  3007.         mov   byte ptr cs:list_count,0 ; clear the line counter
  3008.         mov   bl,byte ptr cs:colour 
  3009.         mov   si,offset cs:press_msg
  3010.         call  disp_str_colour         ; display message in current colour
  3011.  
  3012. pause1:
  3013.  
  3014.         mov   ah,8                    ; get key (without echo) into al.
  3015.         int   21h
  3016.         cmp   al,0                    ; if it's a 2-byte code,
  3017.         je    pause1                  ; then go round again.
  3018.  
  3019.                                       ; Cover the message with some spaces
  3020.  
  3021.         disp_ch  CR
  3022.         push_all
  3023.         mov      al,SPACE
  3024.         mov      ah,09
  3025.         mov      bl,WHITE
  3026.         mov      cx,35
  3027.         BIOS_VIDEO
  3028.         pop_all
  3029.  
  3030.         disp_ch CR
  3031.  
  3032.         push_m  <di,si,cx,bx,ax>       ; avoid colour inheritance bug
  3033.         mov     ah,9
  3034.         mov     al,SPACE
  3035.         mov     bl,WHITE               ; attrib
  3036.         call    get_vpage              ; video page into bh
  3037.         mov     cx,1
  3038.         bios_video
  3039.         pop_m   <ax,bx,cx,si,di>
  3040.  
  3041.         pop_all
  3042.         ret
  3043. list_pause    endp
  3044. ;
  3045. copy_to_buffer2   proc
  3046.                                      ; copy arg into buffer. used by L and D
  3047.         mov   ax,cs
  3048.         mov   si,dx
  3049.         add   si,10
  3050.         mov   es,ax
  3051.         mov   di,offset cs:buffer2
  3052.         mov   cl,cs:arg_end
  3053.         mov   ch,0
  3054.  
  3055. cx_not_zero:
  3056.  
  3057.         cld
  3058.         movsb                        ; copy ds:si to es:di
  3059.                                      ; don't use rep prefix cos we need
  3060.                                      ; to force chars to lower case when
  3061.                                      ; copied.
  3062.  
  3063.         push  ax
  3064.         dec   di                     ; put it where it was before the movsb
  3065.         mov   al,byte ptr es:[di]    ; get the byte just copied
  3066.         or    al,00100000b           ; make character lower case
  3067.         mov   byte ptr es:[di],al    ; and put it back
  3068.         inc   di                     ; and put di back too
  3069.         pop   ax
  3070.  
  3071.         dec   cx                     ; dec counter
  3072.         cmp   cx,0
  3073.         jne   cx_not_zero
  3074.         ret
  3075. copy_to_buffer2   endp
  3076. ab_order proc                        ; Sort the abbreviation table (in RAM)
  3077.                                      ; so that LHS entries are in ascending
  3078.                                      ; alphabetical order.
  3079.                                      ; Method used is a bubble sort.
  3080.                                      ; This proc is not called explicitly by
  3081.                                      ; the user.  It is called automatically
  3082.                                      ; before a LIST or WRITE, and after a
  3083.                                      ; DELETE or ADD command is processed.
  3084.         push_all
  3085.  
  3086. sort1:
  3087.  
  3088.         mov   byte ptr cs:sort_counter,0                  ; count no. of swaps
  3089.         mov   word ptr cs:sort_pointer,offset cs:ab_table ; pointer into data
  3090.         mov   byte ptr cs:sort_entries,TBL_LEN            ; no of entries
  3091.  
  3092. sort2:
  3093.  
  3094.         cmp   byte ptr cs:sort_entries,1 ; are we pointing at the last entry?
  3095.         ja    sort3                      ; no
  3096.         cmp   byte ptr cs:sort_counter,0 ; We've finished a pass through the
  3097.                                          ; data.  If there were no swaps, we
  3098.                                          ; are sorted.
  3099.         je    sorted
  3100.         jmp   sort1
  3101.  
  3102. sort3:
  3103.  
  3104.         call  sort_compare               ; compare string at pointer with the
  3105.                                          ; following one and set swap_flag = 1
  3106.                                          ; if swap needed, else 0
  3107.  
  3108.         cmp   byte ptr cs:swap_flag,1    ; swap needed?
  3109.         jne   sort4                      ; no
  3110.         call  sort_swap                  ; swap
  3111.         inc   byte ptr cs:sort_counter   ; count swaps needed during the pass
  3112.  
  3113. sort4:
  3114.  
  3115.         add   word ptr cs:sort_pointer,LHS_LEN + RHS_LEN +1 ;point to next str
  3116.         dec   byte ptr cs:sort_entries   ; see how far we've got to go
  3117.         jmp   sort2
  3118.  
  3119. sorted:
  3120.  
  3121.         pop_all
  3122.         ret
  3123. ab_order endp
  3124. ;
  3125. sort_compare proc                       ; compare alphabetically the string
  3126.                                         ; at sort_pointer with the string at
  3127.                                         ; (sort_pointer + lhs_len + rhs_len +1)
  3128.                                         ; If they are in the wrong order, set
  3129.                                         ; swap_flag to 1, else set it to 0.
  3130.                                         ; The strings' length is each lhs_len
  3131.                                         ; characters, as we are only looking at
  3132.                                         ; the left hand sides of table entries.
  3133.  
  3134.         push_all
  3135.         mov   byte ptr cs:swap_flag,0   ; clear flag
  3136.         mov   bp,1                      ; count length of strings
  3137.         mov   si,cs:sort_pointer        ; pointer to 1st string
  3138.         mov   di,si                     ; pointer to second string
  3139.         add   di,lhs_len+ rhs_len + 1
  3140.  
  3141. comp1:
  3142.  
  3143.         mov   ah,byte ptr cs:[si]       ; get byte from 1st string
  3144.         mov   al,byte ptr cs:[di]       ; and a byte from the second
  3145.         cmp   ah,al                     ; compare them
  3146.         jb    compared                  ; they're in the right order
  3147.         je    comp2                     ; or they are the same
  3148.  
  3149.         mov   byte ptr cs:swap_flag,1   ; else set the flag to say 'swap'
  3150.         jmp   compared                  ; and our job is done
  3151.  
  3152. comp2:
  3153.  
  3154.         inc   si                        ; bump up pointers
  3155.         inc   di
  3156.         inc   bp                        ; and change "how many left to compare"
  3157.         cmp   bp,lhs_len + 1            ; whole lhs compared?
  3158.         jne   comp1                     ; no, so compare another
  3159.  
  3160. compared:
  3161.  
  3162.         pop_all                         ; all compared.
  3163.         ret
  3164. sort_compare endp
  3165. ;
  3166. sort_swap proc     ; swap the string at sort_pointer with the one at
  3167.                    ; (sort_pointer + lhs_len + rhs_len + 1).  The string
  3168.                    ; has length (lhs_len + rhs_len + 1).  This routine
  3169.                    ; swaps each byte in turn which, although slower than
  3170.                    ; a rep movsb instruction, avoids having to have a
  3171.                    ; large buffer to use while the swap takes place.
  3172.  
  3173.  
  3174.         push_all
  3175.         mov   bp,LHS_LEN + RHS_LEN + 1  ; length of strings
  3176.         mov   si,cs:sort_pointer        ; pointer to 1st string
  3177.         mov   di,si                     ; pointer to second string
  3178.         add   di,bp
  3179.  
  3180. swap1:
  3181.  
  3182.         mov   ah,byte ptr cs:[si]       ; get byte from 1st string
  3183.         mov   al,byte ptr cs:[di]       ; and a byte from the second
  3184.         mov   byte ptr cs:[si],al       ; and write them back...
  3185.         mov   byte ptr cs:[di],ah       ; in reverse order
  3186.         inc   si                        ; bump up pointers
  3187.         inc   di
  3188.         dec   bp                        ; and update counter
  3189.         cmp   bp,0                      ; all swapped?
  3190.         jne   swap1                     ; no, so swap another
  3191.         pop_all                         ; all swapped, so we're done
  3192.         ret
  3193. sort_swap endp
  3194. ;
  3195. to_lower       proc
  3196.  
  3197.                                         ; Force the LHS part of an alias
  3198.                                         ; in an ALIAS A command to lower case.
  3199.  
  3200.         push_m <si,ax>
  3201.         mov    si,dx                    ; pointer into string
  3202.         add    si,10                    ; point to start of LHS in ALIAS A
  3203.                                         ; command string.
  3204.  
  3205. lower1:
  3206.  
  3207.         mov    ah,byte ptr ds:[si]      ; get char from string
  3208.         cmp    ah,CR                    ; are we done?
  3209.         je     lower2
  3210.         cmp    ah,SPACE
  3211.         je     lower2                   ; stop on space. CR is just for safety
  3212.         cmp    ah,41h
  3213.         jb     dont_lower               ; don't convert if character < 'A'
  3214.         cmp    ah,5ah                   ; or > 'Z'
  3215.         ja     dont_lower
  3216.         or     ah, 00100000b            ; else make character lower case
  3217.         mov    byte ptr ds:[si],ah      ; and put it back
  3218.  
  3219. dont_lower:
  3220.  
  3221.         inc    si                       ; point to next char in string
  3222.         jmp    short lower1
  3223.  
  3224. lower2:
  3225.  
  3226.         pop_m  <ax,si>
  3227.         ret
  3228. to_lower       endp
  3229. ;
  3230. list_an_entry  proc                   ; used by ab_list proc. Lists the
  3231.                                       ; table entry which starts at [di].
  3232.  
  3233.                                       ; Display LHS string in current
  3234.                                       ; colour.  Terminates on ascii 0.
  3235.                                       ; However, if the LHS string is of
  3236.                                       ; the maximum permitted length,
  3237.                                       ; there won't be a zero and we run
  3238.                                       ; into the RHS str. So save 1st byte
  3239.                                       ; of RHS string in cs:list_temp 
  3240.                                       ; and put a zero there instead.
  3241.                                       ; Replace saved byte when done.
  3242.                                       ; Do this whatever the length of
  3243.                                       ; the LHS string, as it's not worth
  3244.                                       ; checking! The RHS string always ends
  3245.                                       ; with a 0, so there's no need to
  3246.                                       ; worry about that one.
  3247.  
  3248.         push  bp
  3249.         push  ax
  3250.         mov   bp,di                   ; start of LHS string in cs
  3251.         add   bp,LHS_LEN              ; point to 1st char of RHS string
  3252.         mov   al,byte ptr cs:[bp]     ; get character to save
  3253.         mov   byte ptr cs:list_temp,al; save it
  3254.         mov   byte ptr cs:[bp],0      ; put zero at end of LHS string
  3255.         mov   word ptr cs:list_temp2,bp ; save the address that was altered
  3256.         pop   ax
  3257.         pop   bp
  3258.  
  3259.         push_all
  3260.         mov   si,di                   ; start of string
  3261.         mov   bl,cs:colour            ; set colour
  3262.         call  disp_str_colour         ; display the string
  3263.         pop_all
  3264.  
  3265.         push_m <ax,bp>
  3266.         mov   al,byte ptr cs:list_temp; get original byte
  3267.         mov   bp,word ptr cs:list_temp2 ; get its address
  3268.         mov   byte ptr cs:[bp],al     ; and put the byte back
  3269.         pop_m <bp,ax>
  3270.                                       ; Now put cursor 2 places after LHS so
  3271.                                       ; the RHS strings line up neatly.
  3272.  
  3273.         push_all
  3274.         mov   ah,3                    ; read crsr position
  3275.         call  get_vpage               ; get page into bh
  3276.         bios_video                    ; get crsr row into dh, to preserve
  3277.  
  3278.         mov   ah,2                    ; set crsr position
  3279.         call   get_vpage              ; video page --> bh
  3280.         mov   dl,(LHS_LEN + 2)        ; set column. Leave row as is.
  3281.         bios_video                    ; do it
  3282.         pop_all
  3283.  
  3284.  
  3285.         push_all                      ; display string until 0 byte. 
  3286.         mov   bl,cs:colour            ; current colour
  3287.  
  3288.         add   di,LHS_LEN              ; skip arg
  3289.         mov   si,di                   ; address of string
  3290.         call  disp_str_colour         ; call proc
  3291.         pop_all
  3292.         call  crlf                    ; start a new line
  3293.         ret
  3294. list_an_entry  endp
  3295. ;
  3296. ab_write      proc                    ; ALIAS W <pathname>  saves table
  3297.         call  are_you_sure            ; is user sure?
  3298.         cmp   byte ptr cs:confirm,1   ; did user say yes?
  3299.         jne   write_not_sure          ; abandon if not
  3300.  
  3301.         push_m <ax,bx,cx,dx,bp,si,ds>
  3302.         push ds
  3303.         mov   bp,dx
  3304.         mov   al, byte ptr ds:[bp+1]  ; get length of string
  3305.         cmp   al,7                    ; just ALIAS W typed?
  3306.         jne   write1
  3307.         mov   dx,offset cs:default_fn ; use default file if so.
  3308.  
  3309.         push  ax
  3310.         mov   al,byte ptr cs:[def_dir] ; if this string is full of zeroes,
  3311.                                        ; the default file was not loaded
  3312.         cmp   al,0
  3313.         pop   ax
  3314.         je    not_loaded               ; so use the file name we just set up.
  3315.         mov   dx,offset cs:defdir_hdr  ; If default file WAS loaded at install
  3316.                                        ; time, recover its path.
  3317.  
  3318. not_loaded:
  3319.  
  3320.         push  cs
  3321.         pop   ds
  3322.         jmp   short write2
  3323.  
  3324. write1:
  3325.  
  3326.         mov   ah,0
  3327.         mov   si,ax
  3328.         add   si,2                    ; point to CR terminator
  3329.         add   si,bp
  3330.         mov   byte ptr ds:[si],0      ; change CR to 0 to make asciiz
  3331.         ; 
  3332.         add   dx,10                   ; point to start of filename
  3333.  
  3334. write2:
  3335.  
  3336.         mov   cl,0                    ; no attributes
  3337.         mov   ah,3ch                  ; create file
  3338.         int   21h                     ; do it. Handle -->ax
  3339.         ; 
  3340.         jnc   ab_save_ok              ; continue if no error 
  3341.         call  disk_error_msg
  3342.         jmp   short ab_save_quit      ; else display error msg
  3343.  
  3344. ab_save_ok:
  3345.  
  3346.         mov   bx,ax                   ; write to file. Handle in bx
  3347.         mov   cx,((RHS_LEN + LHS_LEN + 1) * TBL_LEN) + 5 ; table plus signat
  3348.         mov   ax,cs  
  3349.         mov   ds,ax
  3350.         mov   dx,offset cs:table_top  ; point to data area to be saved
  3351.         mov   ah,40h
  3352.         int   21h
  3353.         ; 
  3354.         mov   ah,3eh                  ; close file whose handle is in bx
  3355.         int   21h
  3356.  
  3357. ab_save_quit:
  3358.  
  3359.         pop   ds
  3360.         ; 
  3361.         pop_m <ds,si,bp,dx,cx,bx,ax>
  3362.  
  3363. write_not_sure:
  3364.  
  3365.         ret
  3366. ab_write      endp
  3367. ;
  3368. ab_read       proc                    ; ALIAS R <pathname>  loads a table
  3369.         call  are_you_sure            ; Ask user to confirm
  3370.         cmp   byte ptr cs:confirm,1   ; is user sure?
  3371.         jne   read_not_sure           ; abandon if not
  3372.  
  3373.         push_m <ax,bx,cx,dx,bp,si,ds>
  3374.         push  ds
  3375.         ; 
  3376.         mov   bp,dx
  3377.         mov   al,byte ptr ds:[bp+1]   ; get length of string
  3378.         cmp   al,7                    ; just ALIAS R typed?
  3379.         jne   read1
  3380.         mov   dx,offset cs:default_fn ; assume default filename if so.
  3381.                                       ; However, if a pathed version of the
  3382.                                       ; default file exists, use it instead.
  3383.  
  3384.         push  ax
  3385.         mov   al,byte ptr cs:[def_dir] ; if this string is full of zeroes,
  3386.                                        ; the default file was not loaded
  3387.         cmp   al,0
  3388.         pop   ax
  3389.         je    not_loaded2              ; so use the file name we just set up.
  3390.         mov   dx,offset cs:defdir_hdr  ; If default file WAS loaded at install
  3391.                                        ; time, recover its path.
  3392. not_loaded2:
  3393.  
  3394.         push  cs
  3395.         pop   ds
  3396.         jmp   short read2
  3397.  
  3398. read1:
  3399.  
  3400.         mov   ah,0
  3401.         mov   si,ax
  3402.         add   si,2
  3403.         add   si,bp
  3404.         mov   byte ptr ds:[si],0      ; replace CR with 0
  3405.         ; 
  3406.         add   dx,10                    ; point to start of filename
  3407.  
  3408. read2:
  3409.         mov   ah,3dh
  3410.         mov   al,0                    ; read mode only
  3411.         int   21h                     ; open file for reading
  3412.         ; 
  3413.         jnc   ab_load_ok              ; continue if no error
  3414.         call  disk_error_msg
  3415.         jmp   short ab_l_quit
  3416.  
  3417. ab_load_ok:
  3418.  
  3419.         mov   bx,ax                   ; put handle in correct place
  3420.         mov   cx,((RHS_LEN + LHS_LEN + 1) * TBL_LEN) + 5 ; table plus signat
  3421.         mov   ax,cs
  3422.         mov   ds,ax
  3423.         mov   dx,offset cs:table_top  ; point to destination of loaded bytes
  3424.         mov   ah,3fh                  ; read file
  3425.         int   21h
  3426.         ; 
  3427.         mov   ah,3eh
  3428.         int   21h                     ; close file
  3429.  
  3430. ab_l_quit:
  3431.  
  3432.         pop   ds
  3433.         ; 
  3434.         pop_m <ds,si,bp,dx,cx,bx,ax>
  3435.         call  crlf
  3436. read_not_sure:                        ; come here if user says "No"
  3437.         ret
  3438. ab_read       endp
  3439. get_string_from_kbd proc              ; The DOSEDIT get-string routine
  3440.  
  3441.         call  update_csize            ;make cursor echo insert mode
  3442.         cli                           ;turn interrupts off
  3443.         mov   word ptr cs:oldsp,sp    ;save the old stack pointer
  3444.         mov   word ptr cs:oldsp+2,ss
  3445.         mov   ss,cs:codeseg           ;make a local stack
  3446.         mov   sp,offset stcktop       ;set stack pointer to top of stack
  3447.         sti                           ;turn interrupts back on
  3448.         push  ax                      ;save registers
  3449.         call  bufkey                  ;do buffer keyboard input
  3450.         pop   ax                      ;restore registers
  3451. ;
  3452.         cli                           ;turn interrupts off
  3453.         mov   ss,word ptr cs:oldsp+2  ;restore the old stack
  3454.         mov   sp,word ptr cs:oldsp
  3455.         sti                           ;turn interrupts back on
  3456.         call  small_cursor            ; restore cursor size.
  3457.         ret
  3458. ;
  3459. get_string_from_kbd endp
  3460.  
  3461.                                       ;function to emulate the dos buffered
  3462.                                       ;keyboard input routine int 21 ah=0Ah.
  3463.  
  3464.                                       ;Call to get buffered input from the
  3465.                                       ;keyboard using the tiny editor.
  3466.                                       ;Entry:
  3467.                                       ;ds:dx -> input buffer for the string
  3468.                                       ;ds:dx+0 = number of chars in buffer
  3469.                                       ;Exit:
  3470.                                       ;ds:dx+1 = number of chars entered.
  3471.                                       ;ds:dx+2 -> string terminated by CR.
  3472. bufkey:
  3473.  
  3474.         push_all
  3475. ;
  3476.         mov   ax,ds                   ;es:di -> string storage
  3477.         mov   es,ax
  3478.         mov   di,dx
  3479. ;
  3480.         mov   cl,[di]                 ;cl = max number of char to accept
  3481.         mov   ch,0                    ;cx = max number of char to accept
  3482.         dec   cx                      ;sub 1 to make space for the cr
  3483.         call  tinyedt                 ;get the string
  3484. ;
  3485.         mov   al,CR                   ;echo the return
  3486.         call  putc
  3487. ;
  3488.         call  strlen                  ;compute the string length     
  3489.         inc   di                      ;es:di -> string length storage
  3490.         mov   es:[di],cl              ;save the string length
  3491.         inc   di                      ;es:di -> storage for the string
  3492. ;
  3493.         call  cpystr                  ;copy the string into buffer
  3494.         mov   byte ptr es:[di],cr     ;terminate the string with cr
  3495. ;
  3496.         pop_all
  3497.         ret
  3498.  
  3499.                                       ;call to move output string
  3500.                                       ;Entry:
  3501.                                       ;cs:si -> input string terminated by 0
  3502.                                       ;es:di -> destination for string
  3503.                                       ;Exit:
  3504.                                       ;cs:si -> 0 in source string
  3505.                                       ;es:di -> 0 in destination string
  3506.                                       ;ax = undefined
  3507. cpystr:
  3508.  
  3509.         mov   al,cs:[si]              ;get char from source string
  3510.         mov   es:[di],al              ;write the destination string
  3511.         cmp   al,0                    ;is this the termiation char?
  3512.         jz    cpystr1                 ;yes, string moved
  3513.         inc   si                      ;inc the from pointer
  3514.         inc   di                      ;inc the two pointer
  3515.         jmp   cpystr                  ;loop till done
  3516.  
  3517. cpystr1:
  3518.  
  3519.         ret
  3520. ;
  3521.                                       ;Little line editor
  3522.                                       ;Call to get a single line of text from
  3523.                                       ;the keyboard with editing.
  3524.                                       ;Entry:
  3525.                                       ;cx = max chars to accept, excl null.
  3526.                                       ;Exit:
  3527.                                       ;cs:si -> string terminated with 0
  3528.  
  3529.  
  3530. tinyedt:
  3531.  
  3532.         push   ax                      ;save registers
  3533.         push   bx
  3534.         push   cx
  3535.         push   dx
  3536.         push   bp
  3537.         push   di
  3538.         push   ds
  3539.         push   es
  3540.  
  3541.         mov    ax,cs                   ;data segment = code segment
  3542.         mov    ds,ax
  3543.         mov    maxchar,cx              ;save the max number of characters
  3544.         call   initlin                 ;begin editing a new line
  3545.  
  3546.         call   dcinitlin               ; Do special init functions for DOS
  3547.                                        ; compatibility.
  3548.  
  3549. tinyed1:
  3550.  
  3551.         call   getc                    ;get a character
  3552.         cmp    ax,prf_trigger          ; is char the prf key?
  3553.         je     tiny22
  3554.         mov    byte ptr cs:prf_multi,0 ; clear flag used to detect multiple
  3555.                                        ; presses of the prf key.
  3556. tiny22:
  3557.  
  3558.         cmp    ax,it_key
  3559.         je     tiny2
  3560.         mov    byte ptr cs:it_multi,0
  3561.  
  3562. tiny2:
  3563.  
  3564.         cmp    ax,F6Key               ; Translate F6 to Ctrl-Z
  3565.         jne    tiny9
  3566.         mov    ax,01Ah
  3567.  
  3568. tiny9:
  3569.  
  3570.         cmp    ax,CR                   ;is the key a return?
  3571.         je     tinyed2                 ;yes, done editing the line
  3572.         mov    bx,offset cmndtbl       ;bx -> table of keys and commands
  3573.         call   gotocmd                 ;lookup the command and execute
  3574.         call   update                  ;update the display
  3575.         jmp    tinyed1
  3576.  
  3577. tinyed2:
  3578.  
  3579.         call   begline                 ;move the cursor to the beginning
  3580.         call   update                  ;redraw the display
  3581.         call   endline                 ;remove the bubble in text
  3582.         mov    si,cursorb              ;si -> beginning of the cursor
  3583.         mov    byte ptr [si],0         ;terminate the string
  3584.         mov    si,offset bublbeg       ;cs:si -> beginning of the string
  3585.         call   strlen                  ;compute the string length
  3586.         cmp    cx,shrtstr              ;is the string too short to save?
  3587.         jbe    tinyed3                 ;yes, don't save it
  3588.         call   cmdput                  ;no, long enough, record the line
  3589.  
  3590. tinyed3:
  3591.  
  3592.         pop    es
  3593.         pop    ds
  3594.         pop    di
  3595.         pop    bp
  3596.         pop    dx
  3597.         pop    cx
  3598.         pop    bx
  3599.         pop    ax
  3600.         ret
  3601.  
  3602.  
  3603.                                       ;This routine branches to a command
  3604.                                       ;based on table lookup.
  3605.                                       ;Entry:
  3606.                                       ;ax = command number to lookup in table
  3607.                                       ;bx -> beginning of lookup table
  3608.                                       ;Exit:
  3609.                                       ;ax = command number
  3610.                                       ;pc = command subroutine address
  3611.                                       ;Table Format:     
  3612.                                       ;match word,branch word
  3613.                                       ;last match word must be 0,
  3614.                                       ;the addr is the no match routine.
  3615.  
  3616. gotocmd:
  3617.  
  3618.         cmp   ax,0                    ;is it a null command?
  3619.         jz    gotocd3                 ;yes, skip it
  3620.  
  3621. gotocd1:
  3622.  
  3623.         cmp   [bx],ax                 ;does table entry match command number?
  3624.         je    gotocd2                 ;yes, go do that command
  3625.         cmp   byte ptr [bx],0         ;is this the end of the table?
  3626.         je    gotocd2                 ;yes, execute the no match command
  3627.         add   bx,4                    ;bx -> next table entry
  3628.         jmp   gotocd1                 ;go test next table entry
  3629.  
  3630. gotocd2:
  3631.  
  3632.         add   bx,2                    ;bx -> branch word
  3633.         jmp   word ptr [bx]           ;execute the routine
  3634.  
  3635. gotocd3:
  3636.  
  3637.         ret
  3638. ;
  3639.                                       ;call to begin editing a new line
  3640. initlin:
  3641.  
  3642.         call   vidstat                ;get screen width and display page
  3643.         mov    al,ah                  ;al = screen width
  3644.         mov    ah,0                   ;ax = screen width
  3645.         mov    scrnwdt,ax             ;save screen width
  3646.         mov    disppag,bh             ;save the display page
  3647. ;
  3648.         call   getcpos                ;get the cursor position
  3649.         mov    cursory,dh             ;save cursor position in y
  3650.         mov    al,dl                  ;al = cursor position in x
  3651.         mov    ah,0                   ;ax = cursor position in x
  3652.         mov    cursorx,ax             ;save cursor position in x
  3653.         mov    leftx,ax               ;save x position of the left most spot
  3654. ;
  3655.         mov    ax,scrnwdt             ;ax = width of the screen
  3656.         sub    ax,leftx               ;ax = length of editor line
  3657.         mov    linelen,ax             ;save editor line length
  3658. ;
  3659.         call   delline                ;delete everything in the buffer
  3660. ;
  3661.         mov    si,offset scrnimg      ;fill image buffer with zeros
  3662.         mov    cx,maxswdt             ;cx = buffer size
  3663.  
  3664. initln1:
  3665.  
  3666.         mov    byte ptr [si],0        ;put in a zero
  3667.         inc    si                     ;si -> next spot in the buffer
  3668.         loop   initln1                ;loop till done
  3669.         ret
  3670. ;
  3671.  
  3672. dcinitlin:                            ; Initialize for DOS compatibility.
  3673.                                       ; As we enter the line editor, cmdpnt
  3674.                                       ; points to where, in the history
  3675.                                       ; buffer, the command about to be
  3676.                                       ; entered will start.  Get the text of
  3677.                                       ; the PREVIOUS command and store it in
  3678.                                       ; dcbuffer.  This is the command that
  3679.                                       ; will be recalled if user presses the
  3680.                                       ; invisible DOS-like editing keys.
  3681.  
  3682.         push_m  <bx,si,di,ax>
  3683.         call    cmdprev               ; get start of previous command into si
  3684.  
  3685.                                       ; Now copy the command into dcbuffer.
  3686.  
  3687.         mov     di,offset cs:dcbuffer     ; destination
  3688.         mov     word ptr cs:dcpointer,di  ; initialise dcpointer
  3689.         push    si
  3690.         call    cmdnext
  3691.         pop     si
  3692.  
  3693. dcinit2:
  3694.  
  3695.         mov     ah,byte ptr cs:[si]   ; get byte from command buffer
  3696.         mov     byte ptr cs:[di],ah   ; put in destination
  3697.         cmp     ah,0                  ; are we done?
  3698.         je      dcinit1
  3699.         call    cmdinc                ; get next byte from buffer
  3700.         inc     di
  3701.         jmp     short dcinit2
  3702.  
  3703. dcinit1:
  3704.  
  3705.         pop_m   <ax,di,si,bx>
  3706.         ret
  3707.  
  3708.                                       ;call to initialize the tiny editor
  3709. inittny:
  3710.  
  3711.         call   vidstat                ;get the display page
  3712.         mov    disppag,bh             ;save the display page
  3713.         mov    cursorb,offset bublbeg    ;set pointer to cursor beginning
  3714.         mov    cursore,offset bublend    ;set pointer to cursor end
  3715.         call   noundel                ;mark nothing to undelete
  3716.         call   cmdinit                ;initialize the old command recorder
  3717.         ret
  3718.  
  3719.                                         ;Editor commands
  3720.  
  3721.  
  3722. F3proc:                                 ; Call to implement the F3 key, and
  3723.                                         ; make it work like it does with DOS.
  3724.  
  3725.  
  3726.         mov     si,cs:dcpointer
  3727.         push    ax
  3728.         push    bx
  3729.         mov     ax,word ptr cs:cursorb
  3730.         mov     bx,offset cs:bublbeg
  3731.         sub     ax,bx                   ; AX = number of chars left of cursor
  3732.         push    ax
  3733.         call    delline                 ; delete whats in the buffer now. Can't
  3734.                                         ; do this before calculating ax, cos
  3735.                                         ; it destroys cursorb.
  3736.         pop     ax
  3737.         add     word ptr cs:cursorb,ax  ; Move destination for the incoming
  3738.                                         ; characters past the ones already
  3739.                                         ; typed.
  3740.         pop     bx
  3741.         pop     ax
  3742. ;
  3743.                                         ;Now carry on like a normal cursup.
  3744. f3proc1:
  3745.  
  3746.         call    cmdotrg                 ;get a character from the last command
  3747.         cmp     al,0                    ;is it the termination char?
  3748.         jz      f3proc2                 ;yes
  3749.         cmp     al,0FFh
  3750.         je      f3proc1
  3751.         call    putin                   ;no, place the char in the bubble
  3752.         jmp     f3proc1
  3753. ;
  3754. f3proc2:
  3755.  
  3756.         call    noundel                 ;mark nothing undeletable
  3757.         call    setcol                  ;update start display column number
  3758.         call    cmdnext
  3759.         ret
  3760.  
  3761.  
  3762.                                       ;Call to move the cursor up one line,
  3763.                                       ;show previous command in buffer.
  3764. cursup:
  3765.  
  3766.         call   delline                ;delete what's in the buffer now
  3767.         call   cmdprev                ;si -> previous command
  3768.  
  3769. cursup1:
  3770.  
  3771.         call   cmdotrg                ;get a character from the last command
  3772.         cmp    al,0                   ;is it the termination char?
  3773.         jz     cursup2                ;yes
  3774.         call   putin                  ;no, place the char in the bubble
  3775.         jmp    cursup1
  3776.  
  3777. cursup2:
  3778.  
  3779.         call   noundel                ;mark nothing undeletable
  3780.         call   setcol                 ;update start display column number
  3781.         ret
  3782.  
  3783.                                       ;call to move the cursor down one line,
  3784.                                       ;show next command in buffer.
  3785.  
  3786. cursdn:
  3787.  
  3788.         call   delline                ;delete whats in the buffer now
  3789.         call   cmdnext                ;si -> next command
  3790.  
  3791. cursdn1:
  3792.  
  3793.         call   cmdotrg                ;get a character from the next command
  3794.         cmp    al,0                   ;is it the termination char?
  3795.         jz     cursdn2                ;yes
  3796.         call   putin                  ;no, place the char in the bubble
  3797.         jmp    cursdn1
  3798.  
  3799. cursdn2:
  3800.  
  3801.         call   noundel                ;mark nothing undeletable
  3802.         call   setcol                 ;update start display column number
  3803.         ret
  3804.  
  3805.                                       ;Call to move the cursor to beginning
  3806.                                       ;of the line.
  3807. begline:
  3808.  
  3809.         cmp    cursorb,offset bublbeg ;is the cursor at the beginning?
  3810.         je     beglin1                ;yes, all done
  3811.         call   curslf                 ;move the cursor over 1
  3812.         jmp    begline
  3813.  
  3814. beglin1:
  3815.  
  3816.         ret
  3817.  
  3818.                                       ;Call to move the cursor to the end of
  3819.                                       ;the line.
  3820.  
  3821. endline:
  3822.  
  3823.         cmp    cursore,offset bublend ;is the cursor at the end?
  3824.         je     endlin1                ;yes, all done
  3825.         call   cursrt                 ;move the cursor over 1
  3826.         jmp    endline
  3827.  
  3828. endlin1:
  3829.  
  3830.         ret
  3831.  
  3832.                                       ;call to move the cursor left one word
  3833. wordl:
  3834.  
  3835.         call   curslf                 ;move cursor 1 to the left
  3836.         mov    si,cursorb             ;si -> character on the left of cursor
  3837.         cmp    si,offset bublbeg      ;is it at the beginning of the bubble?
  3838.         je     wordl1                 ;yes, all done moving
  3839.         mov    al,[si-1]              ;al = character on the left
  3840.         call   wordchr                ;is it a legal word character?
  3841.         jnc    wordl                  ;yes, go eat the char
  3842.         call   curslf                 ;move one more across the white char
  3843.  
  3844. wordl1:
  3845.  
  3846.         ret
  3847.  
  3848.                                       ;Call to move the cursor left one word
  3849. wordr:
  3850.  
  3851.         call   cursrt                 ;move one character to the right
  3852.         mov    si,cursore             ;si -> character on the right of cursor
  3853.         cmp    si,offset bublend      ;is it at the end of the bubble?
  3854.         je     wordr1                 ;yes, all done moving
  3855.         mov    al,[si+1]              ;al = character on the right
  3856.         call   wordchr                ;is it a legal word character?
  3857.         jnc    wordr                  ;yes, go eat the char
  3858.         call   cursrt                 ;move one more across the white char
  3859.  
  3860. wordr1:
  3861.  
  3862.         ret
  3863.                                       ;Call to move the cursor left one char
  3864. curslf:
  3865.  
  3866.         cmp    cursorb,offset bublbeg ;is the cursor at the beginning?
  3867.         je     curslf1                ;yes, don't move it
  3868.         dec    cursorb                ;cursorb -> character left of cursor
  3869.         mov    si,cursorb             ;si -> cursor beginning
  3870.         mov    di,cursore             ;di -> cursor end
  3871.         mov    al,[si]                ;al = character left of the cursor
  3872.         mov    [di],al                ;move character right of the cursor
  3873.         dec    cursore                ;cursore -> end of the new cursor
  3874.         call   noundel                ;mark nothing undeletable
  3875.         call   setcol                 ;update start display column number
  3876.  
  3877. curslf1:
  3878.  
  3879.         ret
  3880.  
  3881.                                       ;Call to move the cursor right one char
  3882. cursrt:
  3883.  
  3884.         cmp    cursore,offset bublend ;is the cursor at the end?
  3885.         je     cursrt1                ;yes, don't move it
  3886.         inc    cursore                ;cursore -> character right of cursor
  3887.         mov    si,cursorb             ;si -> cursor beginning
  3888.         mov    di,cursore             ;di -> cursor end
  3889.         mov    al,[di]                ;al = character right of the cursor
  3890.         mov    [si],al                ;move character left of the cursor
  3891.         inc    cursorb                ;cursorb -> new beginning of the cursor
  3892.         call   noundel                ;mark nothing undeletable
  3893.         call   setcol                 ;update start display column number
  3894.  
  3895. cursrt1:
  3896.  
  3897.         ret
  3898.  
  3899.                                       ;call to delete the line the cursor's on
  3900. delline:
  3901.  
  3902.         call   dellinl                  ;delete everything to the left
  3903.         call   dellinr                  ;delete everything to the right
  3904.  
  3905.         ret
  3906.  
  3907. escproc:
  3908.  
  3909.         call   delline                  ; When user hits ESC, delete the
  3910.                                         ; current line, and reset dcpointer
  3911.         push   si
  3912.         mov    si,offset cs:dcbuffer
  3913.         mov    word ptr cs:dcpointer,si
  3914.         pop    si
  3915.         ret
  3916. ;
  3917.                                       ;call to delete all char to beginning
  3918.                                       ;of line.
  3919. dellinl:
  3920.  
  3921.         cmp    cursorb,offset bublbeg ;is the cursor at the beginning?
  3922.         je     dellnl1                ;yes, all deleted
  3923.         call   delchrl                ;no, delete char on the left
  3924.         jmp    dellinl                ;loop till all gone
  3925.  
  3926. dellnl1:
  3927.  
  3928.         ret
  3929.  
  3930.                                       ;call to delete to end of line
  3931. dellinr:
  3932.  
  3933.         cmp    cursore,offset bublend ;is the cursor at the end?
  3934.         je     dellnr1                ;yes, all deleted
  3935.         call   delchrr                ;no, delete char on the right
  3936.         jmp    dellinr                ;loop till all gone
  3937.  
  3938. dellnr1:
  3939.  
  3940.         ret
  3941.  
  3942.                                       ;call to delete word left of the cursor
  3943. delwrdl:
  3944.  
  3945.         call   delchrl                ;delete the character to the left
  3946.         mov    si,cursorb             ;si -> character on the left of cursor
  3947.         cmp    si,offset bublbeg      ;is it at the beginning of the bubble?
  3948.         je     delwrl1                ;yes, all done deleting
  3949.         mov    al,[si-1]              ;al = character on the left
  3950.         call   wordchr                ;is it a legal word character?
  3951.         jnc    delwrdl                ;yes, go eat the char
  3952.  
  3953. delwrl1:
  3954.  
  3955.         ret
  3956.  
  3957.                                       ;call to delete a word right
  3958.                                       ;of the cursor.
  3959. delwrdr:
  3960.  
  3961.         call   delchrr                ;delete the character to the right
  3962.         mov    si,cursore             ;si -> character on the right of cursor
  3963.         cmp    si,offset bublend      ;is it at the end of the bubble?
  3964.         je     delwrr1                ;yes, all done deleting
  3965.         mov    al,[si+1]              ;al = character on the right
  3966.         call   wordchr                ;is it a legal word character?
  3967.         jnc    delwrdr                ;yes, go eat the char
  3968.  
  3969. delwrr1:
  3970.  
  3971.         ret
  3972.  
  3973.                                       ;call to delete char left of cursor
  3974. delchrl:
  3975.  
  3976.         cmp    cursorb,offset bublbeg ;is the cursor at the beginning?
  3977.         je     delchl1                ;yes, don't delete
  3978.         dec    cursorb                ;delete the character
  3979.         inc    unleft                 ;make the character undeletable
  3980.         call   setcol                 ;update start display column number
  3981.  
  3982. delchl1:
  3983.  
  3984.         ret
  3985.  
  3986.  
  3987. delchrr:
  3988.  
  3989.                                       ; Call to delete char right of cursor
  3990.                                       ; However, if user hasn't typed any
  3991.                                       ; chars yet, delete a character from the
  3992.                                       ; dcbuffer.
  3993.  
  3994.  
  3995.         push    bx
  3996.         call    bublcnt               ; bx <-- no of chars typed
  3997.         cmp     bx,0
  3998.         pop     bx
  3999.         jne     del_right
  4000.  
  4001.                                       ; No chars have been typed, so
  4002.                                       ; effectively delete a char from the
  4003.                                       ; dcbuffer by incrementing dcpointer.
  4004.  
  4005.         inc     word ptr cs:dcpointer
  4006.         ret
  4007.  
  4008.  
  4009. del_right:
  4010.  
  4011.         cmp    cursore,offset bublend ;is the cursor at the end?
  4012.         je     del_dcbuff             ;yes, so delete from dcbuffer instead
  4013.         inc    cursore                ;delete the character
  4014.         inc    unright                ;make the character undeletable
  4015.         call   setcol                 ;update start display column number
  4016.  
  4017. delchr1:
  4018.  
  4019.         ret
  4020.  
  4021. del_dcbuff:
  4022.  
  4023.         inc  byte ptr cs:dcpointer
  4024.         ret
  4025.  
  4026.                                       ;call to undelete text from the buffer
  4027. undelet:
  4028.  
  4029.         mov    ax,unleft              ;al = # of char to undelete on left
  4030.         add    cursorb,ax             ;undelete on the left
  4031.         mov    ax,unright             ;al = # of char to undelete on right
  4032.         sub    cursore,ax             ;undelete on the right
  4033.         call   noundel                ;mark nothing undeletable
  4034.         call   setcol                 ;update start display column number
  4035.         ret
  4036.  
  4037.                                       ;call to place a character in the edit
  4038.                                       ;buffer, filter out trash first
  4039. nomatch:
  4040.  
  4041.         call   filter                 ;filter out trash
  4042.         jc     nomtch1                ;branch on trash
  4043.         call   putin                  ;else insert character in edit buffer
  4044.         call   noundel                ;mark nothing undeletable
  4045.         call   setcol                 ;update start display column number
  4046.  
  4047. nomtch1:
  4048.  
  4049.         ret
  4050.  
  4051.                                       ;Editor Display Functions
  4052.  
  4053.                                       ;call to update the display line
  4054. update:
  4055.  
  4056.         push   ax                     ;save registers
  4057.         push   bx
  4058.         push   dx
  4059.         push   si
  4060.         push   di
  4061.         mov    si,offset bublbeg      ;si -> first char in bubble
  4062.         mov    bx,startx              ;bx = start column # of display line
  4063.         call   findcol                ;si -> first character to display
  4064.         mov    di,offset scrnimg      ;di -> screen image buffer
  4065.         mov    updatex,0              ;x pos on display line to update
  4066.  
  4067. update1:
  4068.  
  4069.         cmp    si,cursorb             ;does si -> the cursor in the bubble?
  4070.         jne    update2                ;no
  4071.         mov    ax,updatex             ;yes, save the editor cursor position
  4072.         add    ax,leftx               ;add the starting left column number
  4073.         mov    edcursx,ax
  4074.         mov    si,cursore             ;si -> end of cursor marker
  4075.         inc    si                     ;si -> first char right of the cursor
  4076.  
  4077. update2:
  4078.  
  4079.         cmp    si,offset bublend+1    ;does si -> end of the buffer
  4080.         je     update5                ;yes, go blank end of line
  4081.         mov    al,[si]                ;al = next char to display
  4082.         inc    si                     ;si -> next char in the bubble
  4083.         cmp    al,tab                 ;is the character a tab?
  4084.         jne    update4                ;no, go display the character
  4085.  
  4086. update3:
  4087.  
  4088.         mov    al,' '                 ;yes, expand the tab, display a blank
  4089.         call   updatec                ;display the blank
  4090.         jz     update6                ;branch if update complete
  4091.         mov    ax,updatex             ;ax = current update column
  4092.         add    ax,startx              ;ax = x pos from start of edit line
  4093.         and    ax,111b                ;ax = column mod 8
  4094.         jnz    update3                ;loop till tab expanded
  4095.         jmp    update1                ;go display the next character
  4096.  
  4097. update4:
  4098.  
  4099.         call   updatec                ;display a normal character
  4100.         jz     update6                ;branch if update complete
  4101.         jmp    update1                ;go display the next character
  4102.  
  4103. update5:
  4104.  
  4105.         mov    ax,linelen             ;blank end of line
  4106.         dec    ax                     ;ax = right most column number
  4107.         cmp    ax,updatex             ;has the full screen been displayed?
  4108.         jz     update6                ;yes, all done
  4109.         cmp    byte ptr [di],0        ;has this character never been changed?
  4110.         jz     update6                ;yes, don't change it
  4111.         mov    al,' '                 ;end of line, display blanks
  4112.         call   updatec                ;display the character
  4113.         jnz    update1                ;go display next char if not done
  4114.  
  4115. update6:
  4116.  
  4117.         mov    dx,edcursx             ;position the hardware editor cursor
  4118.         call   setcurx
  4119.         mov    cursorx,dx             ;save the cursor x value
  4120.         pop    di                     ;restore registers and return
  4121.         pop    si
  4122.         pop    dx
  4123.         pop    bx
  4124.         pop    ax
  4125.         ret
  4126.  
  4127.                                       ;call to update a single char on display
  4128.                                       ;Entry:
  4129.                                       ;al = character to write
  4130.                                       ;di -> char in same pos on screen
  4131.                                       ;cursorx = pos of hardware cursor in x
  4132.                                       ;updatex = next x loc to update on scrn
  4133.                                       ;Exit:
  4134.                                       ;cursorx = loc of the hw cursor in x
  4135.                                       ;updatex = new x loc to update on scr
  4136.                                       ;          next time
  4137.                                       ;di -> next character in screen image
  4138.                                       ;z flag set if line fully displayed
  4139.  
  4140. updatec:
  4141.  
  4142.         cmp    al,[di]                ;is the char already shown?
  4143.         je     updatc2                ;yes, don't change it
  4144.         mov    dx,updatex             ;no, must display the character
  4145.         add    dx,leftx               ;dl = desired x location to update
  4146.         cmp    cursorx,dx             ;is the cursor in the correct spot?
  4147.         je     updatc1                ;yes, don't need to move it
  4148.         call   setcurx                ;no, set the cursor column
  4149.         mov    cursorx,dx             ;save the cursor x value
  4150.  
  4151. updatc1:
  4152.  
  4153.         call   putc                   ;display the character
  4154.         inc    cursorx                ;increment the hardware cursor column
  4155.         mov    [di],al                ;put the character in the image buffer
  4156.  
  4157. updatc2:
  4158.  
  4159.         inc    updatex                ;increment the next update column no.
  4160.         inc    di                     ;di -> next char in image buffer
  4161.         mov    ax,linelen             ;ax = line length
  4162.         dec    ax                     ;ax = left most column, line relative
  4163.         cmp    ax,updatex             ;set z flag if display line is full
  4164.         ret
  4165.  
  4166.  
  4167.                                       ;Primitive Editor Functions
  4168.  
  4169.                                       ;call to filter out unwanted characters
  4170.                                       ;Entry:
  4171.                                       ;ax = keyboard character
  4172.                                       ;Exit:
  4173.                                       ;ax = keyboard character
  4174.                                       ;carry set if key filter out
  4175.                                       ;all other registers unchanged
  4176.  
  4177. filter:
  4178.  
  4179.         cmp    al,LF                  ;is it a line feed?
  4180.         je     filter2                ;yes, filter it out
  4181.  
  4182. filter1:
  4183.  
  4184.         clc                           ;don't filter
  4185.         ret                           ;return with no carry
  4186.  
  4187. filter2:
  4188.  
  4189.         stc                           ;do filter the character
  4190.         ret                           ;return with no carry
  4191.  
  4192.                                       ;insert a char into bubble buffer,
  4193.                                       ;no filtering
  4194.                                       ;Entry:
  4195.                                       ;al = character
  4196.                                       ;Exit:
  4197.                                       ;all registers unchanged
  4198.  
  4199. putin:
  4200.  
  4201.         push   ax                     ;save registers
  4202.         push   si
  4203.         call   bublcnt                ;bx = number of characters in bubble
  4204.         cmp    bx,maxchar             ;are more characters allowed?
  4205.         jae    putin1                 ;no, trash the character
  4206.         mov    si,cursorb             ;si -> beginning of the cursor
  4207.         mov    [si],al                ;put the character in the bubble
  4208.         inc    si                     ;si -> next spot in the bubble
  4209.         cmp    si,cursore             ;is the bubble full?
  4210.         je     putin1                 ;yes, don't update the cursor position
  4211.         mov    cursorb,si             ;update the beginning of the cursor
  4212.  
  4213. putin1:
  4214.  
  4215.         pop    si                     ;restore registers
  4216.         pop    ax
  4217.  
  4218.                                       ; If insert mode is off, make a call
  4219.                                       ; to dellchrr, to delete the character
  4220.                                       ; to the right of the cursor.  This
  4221.                                       ; is how we achieve overwrite mode.
  4222.  
  4223.         cmp    byte ptr cs:ins_mode,1 ; insert mode on?
  4224.         je     putin2                 ; yes, so we're ok
  4225.         call   delchrr                ; overwrite mode required
  4226.  
  4227. putin2:
  4228.  
  4229.         ret
  4230.  
  4231.                                       ;call to compute the number of
  4232.                                       ;characters in the bubble buffer
  4233.                                       ;Exit:
  4234.                                       ;bx = number of characters in the buffer
  4235.                                       ;all other registers unchanged
  4236.  
  4237. bublcnt:
  4238.  
  4239.         mov    bx,offset bublend      ;add char count before & after bubble
  4240.         sub    bx,cursore
  4241.         add    bx,cursorb
  4242.         sub    bx,offset bublbeg
  4243.         ret
  4244.  
  4245.                                       ;call to mark nothing undeletable
  4246. noundel:
  4247.  
  4248.         mov    unleft,0
  4249.         mov    unright,0
  4250.         ret
  4251.  
  4252.                                       ;find address of char at column n
  4253.                                       ;Enter:
  4254.                                       ;si -> beginning of string
  4255.                                       ;bx = desired column number
  4256.                                       ;Exit:
  4257.                                       ;si -> character at column n
  4258.                                       ;all other registers unchanged
  4259.  
  4260. findcol:
  4261.  
  4262.         push   ax                     ;save registers
  4263.         push   bx
  4264.         push   cx
  4265.         mov    cx,0                   ;cx = column counter
  4266.         cmp    cx,bx                  ;is this the correct column number?
  4267.         je     findcl3                ;yes, all done
  4268.         inc    bx                     ;incrememt the desired column number
  4269.  
  4270. findcl1:
  4271.  
  4272.         mov    al,[si]                ;al = character from string
  4273.         cmp    al,tab                 ;is it a tab?
  4274.         jne    findcl2                ;no, normal character
  4275.         add    cx,8                   ;yes, expand tab, add tab width
  4276.         and    cx,0fff8h              ;cx = column at next tab stop
  4277.         cmp    cx,bx                  ;is this the correct column?
  4278.         jae    findcl3                ;yes, stop looking
  4279.         inc    si                     ;no, si -> next char in string
  4280.         jmp    findcl1                ;branch if this not desired column
  4281.  
  4282. findcl2:
  4283.  
  4284.         inc    cx                     ;no, add 1 column for displayable char
  4285.         cmp    cx,bx                  ;is this the correct column?
  4286.         je     findcl3                ;yes, stop looking
  4287.         inc    si                     ;si -> next char in string
  4288.         jmp    findcl1                ;keep looking
  4289.  
  4290. findcl3:
  4291.  
  4292.         pop    cx                     ;restore registers and return
  4293.         pop    bx
  4294.         pop    ax
  4295.         ret
  4296.  
  4297.                                       ;call to compute the column
  4298.                                       ;number to begin displaying
  4299.  
  4300.                                       ;Entry:
  4301.                                       ;startx = current start col
  4302.                                       ;of display line
  4303.                                       ;Exit:
  4304.                                       ;startx = new starting column
  4305.                                       ;of the display line
  4306.                                       ;all registers unchanged
  4307.  
  4308. setcol:
  4309.  
  4310.         push   ax                     ;save registers
  4311.         push   bx
  4312.         call   colcurs                ;compute cursor column number
  4313.         cmp    bx,startx              ;is the cursor left of the screen?
  4314.         jae    setcol1                ;no
  4315.         mov    startx,bx              ;yes, set the start spot same as crsr
  4316.         jmp    setcol2                ;all done
  4317.  
  4318. setcol1:
  4319.  
  4320.         mov    ax,linelen             ;ax = width of the display line
  4321.         dec    ax                     ;ax = right most display column
  4322.         add    ax,startx              ;ax = x pos of last displayed char
  4323.         cmp    bx,ax
  4324.         jb     setcol2                ;branch if cursor is on the screen
  4325.  
  4326.         sub    bx,linelen             ;cursor right of display line
  4327.         add    bx,2                   ;compute new starting column
  4328.         mov    startx,bx
  4329.  
  4330. setcol2:
  4331.  
  4332.         pop    bx                     ;restore registers and return
  4333.         pop    ax
  4334.         ret
  4335.  
  4336.                                       ;call to compute the column number the
  4337.                                       ;cursor is on, from beginning of line
  4338.                                       ;Exit:
  4339.                                       ;bx = cursor column number
  4340.                                       ;all other registers unchanged
  4341.  
  4342. colcurs:
  4343.  
  4344.         push   ax                     ;save registers
  4345.         push   si
  4346.         mov    si,offset bublbeg      ;si -> first char on line
  4347.         mov    bx,0                   ;zero column counter
  4348.  
  4349. colcur1:
  4350.  
  4351.         cmp    si,cursorb             ;does si -> the cursor?
  4352.         je     colcur3                ;yes, found the cursor column
  4353.         mov    al,[si]                ;get char from line
  4354.         inc    si                     ;si -> next char on line
  4355.         cmp    al,tab                 ;is it a tab?
  4356.         jne    colcur2                ;no, normal character
  4357.         add    bx,8                   ;add distance between tab stops
  4358.         and    bx,0fff8h              ;bx = column of next tab stop
  4359.         jmp    colcur1                ;go check next character
  4360.  
  4361. colcur2:
  4362.  
  4363.         inc    bx                     ;add 1 column for displayable char
  4364.         jmp    colcur1                ;go check next char
  4365.  
  4366. colcur3:
  4367.  
  4368.         pop    si                     ;restore registers and return
  4369.         pop    ax
  4370.         ret
  4371.  
  4372.                                       ;Functions to record and retrieve
  4373.                                       ;past lines edited
  4374.  
  4375.                                       ;call to find the previous command
  4376.                                       ;Exit:
  4377.                                       ;si -> beginning of the previous cmd
  4378.                                       ;all other registers unchanged
  4379.  
  4380. cmdprev:
  4381.  
  4382.         mov    si,cmdpnt              ;si -> current command
  4383.         cmp    si,cmdold              ;is this the oldest command?
  4384.         je     cmdprv1                ;yes, return pointer to this one
  4385.         call   cmdbefr                ;si -> the previous command
  4386.         mov    cmdpnt,si              ;si -> new current command
  4387.  
  4388. cmdprv1:
  4389.  
  4390.         ret
  4391.  
  4392.                                       ;call to find the next command
  4393.                                       ;Exit:
  4394.                                       ;si -> beginning of the next command
  4395.                                       ;all other registers unchanged
  4396.  
  4397. cmdnext:
  4398.  
  4399.         mov    si,cmdpnt              ;si -> current command
  4400.         cmp    si,cmdnew              ;is this the newest command?
  4401.         je     cmdnxt1                ;yes, return pointer to this one
  4402.         call   cmdaftr                ;si -> the next command
  4403.         mov    cmdpnt,si              ;si -> new current command
  4404.  
  4405. cmdnxt1:
  4406.  
  4407.         ret
  4408.  
  4409.                                       ;call to enter cmd into the ring
  4410.                                       ;Entry:
  4411.                                       ;si -> command terminated by zero
  4412.                                       ;to insert into the ring
  4413.  
  4414. cmdput:
  4415.  
  4416.         push   ax                     ;save registers
  4417.         push   si
  4418.         cmp    byte ptr [si],0        ;is it a null command?
  4419.         jz     cmdput2                ;yes, don't put it in
  4420.  
  4421. cmdput1:
  4422.  
  4423.         mov    al,[si]                ;get a character to insert
  4424.         inc    si                     ;si -> next char to insert
  4425.         call   cmdinrg                ;put it in the ring
  4426.         cmp    al,0                   ;is it the termination zero?
  4427.         jnz    cmdput1                ;no, go insert the next one
  4428.  
  4429. cmdput2:
  4430.  
  4431.         mov    si,cmdnew              ;si -> spot for the next new command
  4432.         mov    cmdpnt,si              ;put the command pointer here
  4433.         mov    byte ptr [si],0        ;make new command a null string
  4434.         pop    si                     ;restore registers and return
  4435.         pop    ax
  4436.         ret
  4437.  
  4438.                                       ;call to get a char from the ring
  4439.                                       ;Entry:
  4440.                                       ;si -> character in the ring
  4441.                                       ;Exit:
  4442.                                       ;al = character from the ring
  4443.                                       ;si -> next character in the ring
  4444.  
  4445. cmdotrg:
  4446.  
  4447.         mov    al,[si]                ;get char from the ring
  4448.         call   cmdinc                 ;si -> next char in the ring
  4449.         ret
  4450.  
  4451.                                       ;call to enter a char into the ring
  4452.                                       ;Entry:
  4453.                                       ;al = character to insert
  4454.                                       ;cmdnew -> storage for new cmd char
  4455.                                       ;Exit:
  4456.                                       ;all registers unchanged
  4457.  
  4458. cmdinrg:
  4459.  
  4460.         push   si                     ;save registers
  4461.         mov    si,cmdnew              ;si -> storage for new commands
  4462.         mov    [si],al                ;save the new command character
  4463.         call   cmdinc                 ;increment the pointer
  4464.         mov    cmdnew,si              ;update pointer for new commands
  4465.         cmp    si,cmdold              ;is an old command in the way?
  4466.         jne    cmdinr1                ;no
  4467.         mov    si,cmdold              ;yes, remove the oldest command
  4468.         call   cmdaftr                ;si -> next to oldest command
  4469.         mov    cmdold,si              ;save pointer to new oldest command
  4470.  
  4471. cmdinr1:
  4472.  
  4473.         pop    si
  4474.         ret
  4475.  
  4476.                                       ;call to search for previous command
  4477.                                       ;Entry:
  4478.                                       ;si -> beginning of current command
  4479.                                       ;Exit:
  4480.                                       ;si -> beginning of previous command
  4481.                                       ;all other registers unchanged
  4482.  
  4483. cmdbefr:
  4484.  
  4485.         call   cmddec                 ;si -> termination of previous command
  4486. cmdbfr1:
  4487.  
  4488.         call   cmddec                 ;si -> previous character
  4489.         cmp    byte ptr [si],0        ;does si -> termination char?
  4490.         jnz    cmdbfr1                ;no, keep looping
  4491.         call   cmdinc                 ;si -> first char of command
  4492.         ret
  4493.  
  4494.                                       ;call to search for the next command
  4495.                                       ;Entry:
  4496.                                       ;si -> beginning of current command
  4497.                                       ;Exit:
  4498.                                       ;si -> beginning of next command
  4499.                                       ;all other registers unchanged
  4500.  
  4501. cmdaftr:
  4502.  
  4503.         call   cmdinc                 ;si -> next character
  4504.         cmp    byte ptr [si],0        ;does si -> termination char?
  4505.         jnz    cmdaftr                ;no, keep looping
  4506.         call   cmdinc                 ;si -> first char of command
  4507.         ret
  4508.  
  4509.                                       ;call to increment a pointer into
  4510.                                       ;the commands buffer.
  4511.  
  4512.                                       ;Exit:
  4513.                                       ;si = increment pointer
  4514.                                       ;all other registers unchanged
  4515. cmdinc:
  4516.  
  4517.         inc    si                     ;inc the pointer
  4518.         cmp    si,offset cmdbot       ;is the pointer outside the ring?
  4519.         jbe    cmdinc1                ;no
  4520.         mov    si,offset cmdtop       ;yes, set pointer to the top
  4521.  
  4522. cmdinc1:
  4523.  
  4524.         ret
  4525.  
  4526.                                       ;call to decrement a pointer into the
  4527.                                       ;commands buffer.
  4528.                                       ;Exit:
  4529.                                       ;si = decremented pointer
  4530.                                       ;all other registers unchanged
  4531.  
  4532. cmddec:
  4533.  
  4534.         dec    si                     ;dec the pointer
  4535.         cmp    si,offset cmdtop       ;is the pointer outside the ring?
  4536.         jae    cmddec1                ;no
  4537.         mov    si,offset cmdbot       ;yes, set pointer to the bottom
  4538.  
  4539. cmddec1:
  4540.  
  4541.         ret
  4542.  
  4543.                                       ;call to initialize the command
  4544.                                       ;recording functions.
  4545.  
  4546. cmdinit:
  4547.  
  4548.         mov    si,offset cmdtop       ;si -> beginning of command ring
  4549.         mov    cmdold,si              ;initialize all pointer to top of ring
  4550.         mov    cmdnew,si
  4551.         mov    cmdpnt,si
  4552.         mov    si,offset cmdtop       ;fill command buffer with null strings
  4553.         mov    cx,cmdlen              ;cx = buffer size
  4554.  
  4555. cmdint1:
  4556.  
  4557.         mov    byte ptr [si],0        ;put in a zero
  4558.         inc    si                     ;si -> next spot in the buffer
  4559.         loop   cmdint1                ;loop till done
  4560.         ret
  4561.  
  4562.                                       ;DOS and ROM Interface Functions
  4563.  
  4564.                                       ;call to get the state of the video
  4565.                                       ;Exit:
  4566.                                       ;al = display mode
  4567.                                       ;ah = number of char columns on screen
  4568.                                       ;bh = current active display page
  4569.                                       ;bl = undefined
  4570.                                       ;all other registers unchanged
  4571.  
  4572. vidstat:
  4573.  
  4574.         push   si                     ;save registers
  4575.         push   di
  4576.         mov    ah,15                  ;get the video state
  4577.         bios_video
  4578.         pop    di                     ;restore registers and return
  4579.         pop    si
  4580.         ret
  4581.  
  4582.                                       ;call to get the cursor position
  4583.                                       ;Exit:
  4584.                                       ;dl = cursor position in x
  4585.                                       ;dh = cursor position in y
  4586.                                       ;all other registers unchanged
  4587.  
  4588. getcpos:
  4589.  
  4590.         push   ax                     ;save registers
  4591.         push   bx
  4592.         push   si
  4593.         push   di
  4594.         mov    bh,disppag             ;bh = display page
  4595.         mov    ah,3                   ;read the cursor position
  4596.         bios_video
  4597.         pop    di                     ;restore registers and return
  4598.         pop    si
  4599.         pop    bx
  4600.         pop    ax
  4601.         ret
  4602.  
  4603.                                       ;call to set the cursor x position
  4604.                                       ;Entry:
  4605.                                       ;dl = cursor position in x
  4606.                                       ;Exit:
  4607.                                       ;all registers unchanged
  4608.  
  4609. setcurx:
  4610.  
  4611.         push   ax                     ;save registers
  4612.         push   bx
  4613.         push   si
  4614.         push   di
  4615.         mov    dh,cursory             ;dh = cursor line number
  4616.         mov    bh,disppag             ;bh = display page
  4617.         mov    ah,2                   ;set the cursor position
  4618.         bios_video
  4619.         pop    di                     ;restore registers and return
  4620.         pop    si
  4621.         pop    bx
  4622.         pop    ax
  4623.         ret
  4624.  
  4625.                                       ;call to display a string
  4626.                                       ;Entry:
  4627.                                       ;si -> string terminated by zero
  4628.                                       ;Exit:
  4629.                                       ;all registers unchanged
  4630.  
  4631. puts:
  4632.  
  4633.         push   ax                     ;save registers
  4634.         push   si
  4635.  
  4636. puts1:
  4637.  
  4638.         mov    al,[si]                ;get char from the string
  4639.         inc    si                     ;si -> next char in string
  4640.         cmp    al,0                   ;is it the termination zero?
  4641.         jz     puts2                  ;yes, all done
  4642.         call   putc                   ;display the character
  4643.         jmp    puts1                  ;go display the next character
  4644.  
  4645. puts2:
  4646.  
  4647.         pop    si                     ;restore registers and return
  4648.         pop    ax
  4649.         ret
  4650.  
  4651. putc:                                 ;display char in al
  4652.  
  4653.         disp_ch al
  4654.         ret
  4655.  
  4656.                                       ;call to get a char from the console
  4657.                                       ;keyboard without echo
  4658.                                       ;Exit:
  4659.                                       ;ax = char from keyboard
  4660.                                       ;ah = 1 if extended keycode else 0
  4661.                                       ;all other registers unchanged
  4662.  
  4663. getc:
  4664.  
  4665.         mov    ah,8                   ;read keyboard without echo
  4666.         int    21h
  4667.         cmp    al,0                   ;is it an extended key?
  4668.         jz     getc1                  ;yes, go get the keycode
  4669.         mov    ah,0                   ;no, ax = keyboard code
  4670.         ret
  4671.  
  4672. getc1:
  4673.  
  4674.         mov    ah,8                   ;read keyboard without echo
  4675.         int    21h
  4676.         mov    ah,1                   ;ax = extended keycode
  4677.         ret
  4678.  
  4679.                                       ;Misc Functions
  4680.  
  4681.                                       ;call to compute the length of a string
  4682.                                       ;Entry:
  4683.                                       ;cs:si -> string terminated by zero
  4684.                                       ;Exit:
  4685.                                       ;cx = string length
  4686.                                       ;all other registers unchanges
  4687.  
  4688. strlen:
  4689.  
  4690.         push   si                     ;save registers
  4691.         mov    cx,0                   ;zero the counter
  4692.  
  4693. strlen1:
  4694.  
  4695.         cmp    byte ptr cs:[si],0     ;is this the termination character?
  4696.         jz     strlen2                ;yes, all done
  4697.         inc    si                     ;si -> next char in string
  4698.         inc    cx                     ;inc the char counter
  4699.         jmp    strlen1                ;loop till done
  4700.  
  4701. strlen2:
  4702.  
  4703.         pop    si                     ;restore registers and return
  4704.         ret
  4705.  
  4706.                                       ;call to check for legal word character
  4707.                                       ;Entry:
  4708.                                       ;al = char to test
  4709.                                       ;Exit:
  4710.                                       ;cf set if invalid char
  4711.                                       ;all other registers unchanged
  4712.  
  4713. wordchr:
  4714.  
  4715.         push   bx                     ;save bx
  4716.         mov    bx,'az'                ;is the char a lower case letter?
  4717.         call   chrrang
  4718.         jnc    wordch1                ;yes, return with no carry
  4719.         mov    bx,'AZ'                ;is the char an upper case letter?
  4720.         call   chrrang
  4721.         jnc    wordch1                ;yes, return with no carry
  4722.         mov    bx,'09'                ;is the char a number?
  4723.         call   chrrang                ;return with status in carry
  4724.  
  4725. wordch1:
  4726.  
  4727.         pop    bx                     ;restore bx and return
  4728.         ret
  4729.  
  4730.                                       ;call to test if a character is
  4731.                                       ;between or included by two characters
  4732.                                       ;Entry:
  4733.                                       ;al = char to check
  4734.                                       ;bl = upper match char
  4735.                                       ;bh = low match char
  4736.                                       ;Exit:
  4737.                                       ;cf clear if valid match
  4738.                                       ;bl = undefined
  4739.                                       ;all other registers unchanged
  4740.  
  4741. chrrang:
  4742.  
  4743.         cmp    al,bh                  ;is the char < bh
  4744.         jc     chrrng1                ;yes, no match, return with carry
  4745.         inc    bl                     ;is the char > bl
  4746.         cmp    al,bl                  ;compare with upper limit
  4747.         cmc                           ;invert the carry flag
  4748.  
  4749. chrrng1:
  4750.  
  4751.         ret
  4752. ;
  4753. inskey         proc                    ; Toggle insert mode, cos user has
  4754.                                        ; pressed insert key.
  4755.  
  4756.                                        ; However, if bublcnt = 0, obey the
  4757.                                        ; rules of DOS compatibility and insert
  4758.                                        ; an 0FFh byte into dcbuffer.
  4759.  
  4760.         push   bx
  4761.         call   bublcnt
  4762.         cmp    bx,0                    ; Has user typed anything yet?
  4763.         pop    bx
  4764.         jne    ins_normal              ; If yes, continue normally
  4765.  
  4766.                                        ; Insert a 0FFh byte into dcbuffer,
  4767.                                        ; starting at cs:[dcpointer].
  4768.  
  4769.         push    si
  4770.         mov     si,offset cs:dcbufend  ; start at end of dcbuffer
  4771.         sub     si,2                   ; point to last byte of dcbuffer
  4772.                                        ; before end marker
  4773.         cmp     byte ptr cs:[si],0     ; is there room for a char to be
  4774.                                        ; inserted?
  4775.         je      ins_is_room            ; continue if there's room, ie last
  4776.                                        ; char is zero
  4777.         cmp     byte ptr cs:[si],0FFh
  4778.         je      ins_is_room            ; also continue if last char is 0FFh
  4779.         pop     si                     ; else, tidy up the stack...
  4780.         ret                            ; ...and return.
  4781.  
  4782. ins_is_room:
  4783.  
  4784.         push    bx
  4785.         push    ax
  4786.         mov     bx,word ptr cs:dcpointer
  4787.  
  4788. shift_cont:
  4789.  
  4790.         mov     ah,byte ptr cs:[si]    ; get character from dcbuffer
  4791.         mov     byte ptr cs:[si+1],ah  ; shift it right by one char
  4792.         cmp     si,bx                  ; are we done shifting?
  4793.         je      dun_shifting
  4794.         dec     si
  4795.         jmp     short shift_cont
  4796.  
  4797. dun_shifting:
  4798.  
  4799.         mov     byte ptr cs:[si],0FFh  ; put blank in newly-created space
  4800.         pop     ax
  4801.         pop     bx
  4802.         pop     si
  4803.         ret                            ; End of dcbuffer insert routine
  4804.  
  4805. ins_normal:
  4806.  
  4807.         cmp    byte ptr cs:ins_mode,0  ; is mode currently overwrite?
  4808.         jne    ins01                   ; no, so change to overwrite
  4809.         mov    byte ptr cs:ins_mode,1  ; change to insert mode
  4810.         jmp    short ins02
  4811.  
  4812. ins01:
  4813.  
  4814.         mov    byte ptr cs:ins_mode,0  ; set mode to overwrite
  4815. ins02:
  4816.  
  4817.         call  update_csize             ; update cursor size to reflect mode
  4818.         ret
  4819. inskey        endp
  4820. ;
  4821. update_csize   proc
  4822.  
  4823.         cmp    byte ptr cs:ins_mode,0   ; is mode set to overwrite?
  4824.         jne    ins_csize                ; no, so set csize to insert size
  4825.         call   small_cursor             ; yes, so make small cursor
  4826.         jmp    short ins2
  4827.  
  4828. ins_csize:
  4829.  
  4830.         call   big_cursor
  4831.  
  4832. ins2:
  4833.  
  4834.         ret
  4835. update_csize   endp
  4836. ;
  4837. big_cursor     proc                    ; Add 2 scan lines to crsr height
  4838.  
  4839.         cmp    byte ptr cs:[csize],2   ; is cursor already big?
  4840.         je     is_big                  ; yes, so do nothing
  4841.         push_m <ax,bx,cx,dx,di,si>
  4842.         mov    ah,3
  4843.         call   get_vpage
  4844.         bios_video                         ; returns height of cursor in cl
  4845.         dec    ch
  4846.         dec    ch                          ; increase the height of the cursor
  4847.                                            ; by 2 scan lines.
  4848.         mov    ah,1
  4849.         call   get_vpage
  4850.         bios_video                         ; and set new cursor height
  4851.         mov    byte ptr cs:[csize],2       ; set status to say crsr is big
  4852.         pop_m  <si,di,dx,cx,bx,ax>
  4853.  
  4854. is_big:
  4855.  
  4856.         ret
  4857.  
  4858. big_cursor     endp
  4859. ;
  4860. small_cursor     proc                  ; Shrink crsr height by 2 scan lines
  4861.  
  4862.         cmp    byte ptr cs:[csize],1   ; is cursor already small?
  4863.         je     is_small                ; yes, then do nothing
  4864.         push_m <si,di,ax,bx,cx,dx>
  4865.         mov    ah,3
  4866.         call   get_vpage
  4867.         bios_video                         ; returns start line in ch
  4868.         inc    ch
  4869.         inc    ch                          ; shrink the height of the cursor
  4870.                                            ; by 2 scan lines.
  4871.         mov    ah,1
  4872.         call   get_vpage
  4873.         bios_video                         ; and set new cursor height
  4874.         mov    byte ptr cs:[csize],1       ; set status to say crsr is small
  4875.         pop_m  <dx,cx,bx,ax,di,si>
  4876.  
  4877. is_small:
  4878.  
  4879.         ret
  4880.  
  4881. small_cursor     endp
  4882. ;
  4883. do_prf proc                            ; User pressed prf trigger key for the
  4884.                                        ; first time, while entering a command.
  4885.                                        ; Search the
  4886.                                        ; stored commands for matches with
  4887.                                        ; however many characters the user
  4888.                                        ; has typed so far.
  4889.  
  4890.                                        ; If a match is found, update display.
  4891.  
  4892.                                        ; The order of search is to start at
  4893.                                        ; cmdpnt, which is where the next cmd
  4894.                                        ; to be entered would be stored. We
  4895.                                        ; then work backwards,towards cmdtop,
  4896.                                        ; getting the most recent commands.  We
  4897.                                        ; wrap from cmdtop to cmdbot once, and
  4898.                                        ; searching stops when cmdpnt is
  4899.                                        ; reached for the second time.
  4900.  
  4901.         push   bx
  4902.         call   bublcnt                 ; bx <-- no of chars typed by user
  4903.         cmp    bx,0                    ; has user typed anything yet?
  4904.         pop    bx
  4905.         je     no_prf                  ; no, so do nothing
  4906.  
  4907.         cmp    byte ptr cs:prf_multi,0 ; is this another press of the prf key
  4908.                                        ; straight after the last one?
  4909.         je     no_multi                ; no, so carry on
  4910.  
  4911.         push_all                       ; prepare for a multiple prf
  4912.         mov    si,word ptr cs:prf_pos  ; restore si from last prf proc
  4913.         mov    bp,0                    ; go round the whole stack again
  4914.                                        ; Actually, there's no reason to go
  4915.                                        ; all the way round again.  We SHOULD
  4916.                                        ; save bp the first time round, and
  4917.                                        ; restore it for multiple prf presses.
  4918.         jmp    short prf2
  4919.  
  4920. no_multi:
  4921.  
  4922.         push_all
  4923.         mov    si,word ptr cs:cmdpnt   ; posn where next cmd will be stored
  4924.         mov    bp,0
  4925.  
  4926. prf2:
  4927.  
  4928.         call   cmdbefr                 ; SI now points to the first char of
  4929.                                        ; the latest command.
  4930.         cmp    bp,0                    ; After calling cmdbefr for
  4931.                                        ; the FIRST TIME, save SI in BP.
  4932.         jne    prf1
  4933.         mov    bp,si
  4934.         jmp    short prf3
  4935.  
  4936. prf1:
  4937.  
  4938.         cmp    bp,si                   ; On all but first time round, check
  4939.         jne    prf3                    ; if bp=si.  If so, we've come full
  4940.                                        ; circle and have checked all commands.
  4941.         jmp    prf_done
  4942.  
  4943. prf3:
  4944.  
  4945.         mov    di,offset cs:bublbeg    ; point to first word of user's command
  4946.         call   prf_compare             ; compare word at [si] with one at [di]
  4947.         cmp    byte ptr cs:prf_cflag,1 ; was a match found?
  4948.         je     prf_match               ; yes, so update display
  4949.         jmp    short prf2              ; No match.  Get next cmd from stack
  4950.                                        ; and try again.
  4951. prf_match:
  4952.  
  4953.         mov    word ptr cs:prf_pos,si  ; Match found. Save address of start of
  4954.                                        ; matching command...
  4955.         call   prf_disp                ; ...and put it on screen
  4956.  
  4957. prf_done:
  4958.  
  4959.         mov    byte ptr cs:prf_multi,1 ; set flag.  When any key apart from
  4960.                                        ; the prf trigger is pressed, this flag
  4961.                                        ; gets cleared, so if it is still set
  4962.                                        ; on entry to do_prf next time, then
  4963.                                        ; we have a multiple prf request and
  4964.                                        ; look for the next match, rather than
  4965.                                        ; starting from cmdpnt again.
  4966.  
  4967.  
  4968.         pop_all
  4969.  
  4970. no_prf:
  4971.  
  4972.         ret
  4973. do_prf  endp
  4974. ;
  4975. prf_compare proc
  4976.  
  4977.                                        ; This proc compares the characters
  4978.                                        ; in the user's partly-typed command
  4979.                                        ; with the same number of characters
  4980.                                        ; in the command at [si], which is one
  4981.                                        ; in the dosedit buffer. Sets prf_cflag
  4982.                                        ; if match found.
  4983.  
  4984.                                        ; The chars at [si] is in the dosedit
  4985.                                        ; command buffer, and may wrap around.
  4986.                                        ; Therefore, we can't use a repe cmpsb
  4987.                                        ; for the comparison.  Instead, we keep
  4988.                                        ; calling cmdinc, which increments si
  4989.                                        ; and will wrap from bottom to top of
  4990.                                        ; the command stack if necessary.
  4991.  
  4992.         mov    byte ptr cs:prf_cflag,0      ; clear flag
  4993.         push_m <ax,si,di,bx>
  4994.  
  4995.         call   bublcnt                 ; bx <-- no of chars typed by user.
  4996.                                        ; Used by this proc to count how many
  4997.                                        ; comparisons we need to make.
  4998.  
  4999.         cmp    byte ptr cs:prf_multi,1 ; Is this a multiple prf press?
  5000.         jne    prf_c2                  ; No, so carry on
  5001.         mov    bx,word ptr cs:prf_bx   ; It is a multiple press, so use the
  5002.         jmp    prf_c4                  ; value of bublcnt from last time.
  5003.                                        ; This way, we only look for matches
  5004.                                        ; in the part of the string that the
  5005.                                        ; user actually typed, and not in the
  5006.                                        ; part that prf added last time.
  5007. prf_c2:
  5008.  
  5009.         mov    word ptr cs:prf_bx,bx   ; First time round, save bublcnt value.
  5010.  
  5011. prf_c4:
  5012.  
  5013.         mov    ah,byte ptr cs:[di]     ; get a byte from user's string
  5014.         mov    al,byte ptr cs:[si]     ; and one from command stack
  5015.         or     ax,0010000000100000b    ; force chars to lower case
  5016.         cmp    bx,0                    ; have we compared enough characters?
  5017.         je     prf_c1                  ; yes, then match was found
  5018.         cmp    ah,al                   ; are they equal?
  5019.         jne    prf_c3                  ; no match. Exit and leave flag clear.
  5020.         inc    di                      ; chars are equal, so go get next ones
  5021.         call   cmdinc                  ; inc si, but watch for wrap
  5022.         dec    bx                      ; count no of comparisons made
  5023.         jmp    short prf_c4            ; and off we go again
  5024.  
  5025. prf_c1:
  5026.  
  5027.         mov    byte ptr cs:prf_cflag,1 ; indicate that match was found
  5028.  
  5029. prf_c3:
  5030.  
  5031.         pop_m  <bx,di,si,ax>
  5032.         ret
  5033. prf_compare endp
  5034. ;
  5035. prf_disp proc                         ; If do_prf finds a match, then this
  5036.                                       ; proc is called.  It is almost
  5037.                                       ; identical to cursup, which is called
  5038.                                       ; by the dosedit routine when the user
  5039.                                       ; presses up-arrow to retrieve the
  5040.                                       ; previous command.  However, address
  5041.                                       ; of the cmd to be retrieved is taken
  5042.                                       ; from prf_pos rather than from a call
  5043.                                       ; to cmdprev.
  5044.  
  5045.         push_all
  5046.         call   delline                ;delete what's in the buffer now
  5047.         mov    si,word ptr cs:prf_pos ; get address of matching command that
  5048.                                       ; do_prf found.
  5049.  
  5050. prf_disp1:
  5051.  
  5052.         call   cmdotrg                ;get a character from the last command
  5053.         cmp    al,0                   ;is it the termination char?
  5054.         jz     prf_disp2              ;yes
  5055.         call   putin                  ;no, place the char in the bubble
  5056.         jmp    prf_disp1
  5057.  
  5058. prf_disp2:
  5059.  
  5060.         call   noundel                ;mark nothing undeletable
  5061.         call   setcol                 ;update start display column number
  5062.  
  5063.         pop_all
  5064.         ret                           ; Pointers all set.  The actual update
  5065.                                       ; to the display will happen when the
  5066.                                       ; update proc is called.
  5067.  
  5068. prf_disp endp
  5069. ;
  5070. it_proc proc                           ; Called when user presses the 'it'
  5071.                                        ; key, which is currently F8.
  5072.                                        ; Retrieves all but the first word of
  5073.                                        ; the previous command, and sticks it
  5074.                                        ; on the end of the part-typed command.
  5075.                                        ; Unlike prf, this proc doesn't check
  5076.                                        ; that the first words match.
  5077.  
  5078.  
  5079.         call    cmdprev                 ;SI -> previous command
  5080.         push    si
  5081.  
  5082. it2:
  5083.  
  5084.         cmp     byte ptr cs:[si],SPACE
  5085.         je      it1
  5086.         inc     si
  5087.         jmp     short it2
  5088.  
  5089. it1:
  5090.  
  5091.         inc     si                      ; SI now points to the first char
  5092.                                         ; after the space in the previous
  5093.                                         ; command.  This is where characters
  5094.                                         ; will be retrieved from.
  5095.         push    ax
  5096.         push    bx
  5097.         mov     ax,word ptr cs:cursorb
  5098.         mov     bx,offset cs:bublbeg
  5099.         sub     ax,bx                   ; AX = number of chars left of cursor
  5100.         push    ax
  5101.         call    delline                 ; delete whats in the buffer now. Can't
  5102.                                         ; do this before calculating ax, cos
  5103.                                         ; it destroys cursorb.
  5104.         pop     ax
  5105.  
  5106.         cmp     byte ptr cs:it_multi,1  ; if multiple F8 in operation,
  5107.         jne     it6                     ; then use old cursorb
  5108.         push    bx
  5109.         mov     bx,word ptr cs:it_save
  5110.         mov     word ptr cs:cursorb,bx
  5111.         pop     bx
  5112.         jmp     short it5
  5113.  
  5114. it6:
  5115.  
  5116.         add     word ptr cs:cursorb,ax  ; Move destination for the incoming
  5117.                                         ; characters past the ones already
  5118.                                         ; typed.
  5119.         mov     bx,word ptr cs:cursorb
  5120.         mov     word ptr cs:it_save,bx  ; save cursorb, to use if multiple
  5121.                                         ; presses of F8 detected.
  5122. it5:
  5123.         pop     bx
  5124.         pop     ax
  5125. ;
  5126.         push    si
  5127.         mov     si,word ptr cs:cursorb
  5128.         cmp     byte ptr cs:[si-1],SPACE ; Did user leave a space
  5129.                                          ; before pressing the IT key?
  5130.         pop     si
  5131.         je      it3                      ; Yes, then we're ok
  5132.  
  5133.         push    si
  5134.         mov     si,word ptr cs:cursorb
  5135.         mov     byte ptr cs:[si],SPACE   ; Else force a space into string
  5136.         inc     si
  5137.         mov     word ptr cs:cursorb,si
  5138.         pop     si
  5139.  
  5140.                                         ;Now carry on like a normal cursup.
  5141. it3:
  5142.  
  5143.         call    cmdotrg                 ;get a character from the last command
  5144.         cmp     al,0                    ;is it the termination char?
  5145.         jz      it4                     ;yes
  5146.         call    putin                   ;no, place the char in the bubble
  5147.         jmp     it3
  5148.  
  5149. it4:
  5150.         call    noundel                 ;mark nothing undeletable
  5151.         call    setcol                  ;update start display column number
  5152.         pop     si
  5153.         mov     byte ptr cs:it_multi,1  ; set flag, which is cleared after
  5154.                                         ; getc is called.  If it's still set
  5155.                                         ; on entry to it_proc, then multiple
  5156.                                         ; presses of F8 are occurring.
  5157.         ret
  5158. it_proc endp
  5159. ;
  5160. f1proc  proc                            ; Do nothing if F1 pressed
  5161.         ret
  5162.  
  5163. f1proc  endp
  5164. ;
  5165. pg_up_proc     proc                     ;PgUp moves pointers to start of
  5166.                                         ;command buffer.
  5167.  
  5168.         push   si
  5169.         push   bp
  5170.  
  5171. pgup_top:
  5172.  
  5173.         call   cmdprev                  ; get previous command into si
  5174.         mov    bp,si                    ; and save it in bp
  5175.         call   cmdprev                  ; get previous command again
  5176.         cmp    si,bp                    ; has value changed?
  5177.         je     pgup_done                ; no, so we're at the top
  5178.         jmp    short pgup_top           ; not there yet
  5179.  
  5180. pgup_done:
  5181.  
  5182.         pop    bp
  5183.         pop    si
  5184.         ret
  5185.  
  5186.  
  5187.         ret
  5188. pg_up_proc     endp
  5189. ;
  5190. pg_dn_proc     proc                     ;PgDn moves pointers to end of
  5191.                                         ;command buffer.
  5192.  
  5193.         push   si
  5194.         push   bp
  5195.  
  5196. pgdn_top:
  5197.  
  5198.         call   cmdnext                  ; get next command into si
  5199.         mov    bp,si                    ; and save it in bp
  5200.         call   cmdnext                  ; get next command again
  5201.         cmp    si,bp                    ; has value changed?
  5202.         je     pgdn_done                ; no, so we're at the end
  5203.         jmp    short pgdn_top           ; not there yet
  5204.  
  5205. pgdn_done:
  5206.  
  5207.         pop    bp
  5208.         pop    si
  5209.         ret
  5210. pg_dn_proc     endp
  5211. ;
  5212. also_proc      proc                     ; The F10 key is the 'also' key.
  5213.                                         ; Brings back the first word of the
  5214.                                         ; previous command, up to & including
  5215.                                         ; the first space character.
  5216.  
  5217.  
  5218.         call   delline                ;delete what's in the buffer now
  5219.         call   cmdprev                ;si -> previous command
  5220.         mov    al,0                   ; don't let al be 20h on entry
  5221.  
  5222. also1:
  5223.  
  5224.         cmp    al,SPACE               ; Was last char a space?
  5225.         jz     also2                  ; yes, then we have enough characters
  5226.         call   cmdotrg                ;get a character from the last command
  5227.         cmp    al,0                   ;is it the termination char?
  5228.         jz     also2                  ;yes
  5229.         call   putin                  ;no, place the char in the bubble
  5230.         jmp    also1
  5231.  
  5232. also2:
  5233.  
  5234.         call   noundel                ;mark nothing undeletable
  5235.         call   setcol                 ;update start display column number
  5236.         ret
  5237. also_proc      endp
  5238. ;
  5239.                                       ; Now, a procedure to display a 
  5240.                                       ; string, using a screen 
  5241.                                       ; attribute that can be specified 
  5242.                                       ; by the caller.  On entry, SI 
  5243.                                       ; must point to the offset of the 
  5244.                                       ; string, which must be in the 
  5245.                                       ; CODE SEGMENT. BL should be set 
  5246.                                       ; to the attribute required.  
  5247.                                       ; Strings of longer than 80 
  5248.                                       ; chars should have a crlf at 
  5249.                                       ; the end of each line. 
  5250.                                       ;
  5251.                                       ; Strings should end in a cr,lf so
  5252.                                       ; that the end of this routine can
  5253.                                       ; display a space in white after
  5254.                                       ; displaying the string. If this
  5255.                                       ; is not done, the default colour
  5256.                                       ; is not always re-set properly.
  5257.                                       ;
  5258.                                       ; Always terminates on ascii 0.
  5259.                                       ; Won't terminate on $.
  5260.  
  5261. disp_str_colour        proc
  5262.  
  5263.  
  5264.         call   get_vpage              ; get vpage into bh
  5265.  
  5266.         mov   cx,1                    ; write each char once
  5267.         mov   ax,cs                   ; the string must be in cs, but...
  5268.         cmp   byte ptr cs:echo_flag,1 ; if flag is set, string is in ds
  5269.         jne   all_ok
  5270.         mov   ax,ds
  5271.  
  5272. all_ok:
  5273.  
  5274.         mov   ds,ax
  5275.         cld
  5276.  
  5277. again:
  5278.  
  5279.         lodsb                         ; get char into al
  5280.         cmp   al,0
  5281.         je    done
  5282.         cmp   al,CR 
  5283.         jne   try1
  5284.         disp_ch CR 
  5285.         jmp   short again
  5286.  
  5287. try1:
  5288.  
  5289.         cmp   al,LF
  5290.         jne   try2
  5291.         disp_ch LF
  5292.         jmp   short again
  5293.  
  5294. try2:
  5295.  
  5296.         mov   ah,09h
  5297.         bios_video                    ; disp char
  5298.         push_all
  5299.         mov   ah,3
  5300.         bios_video                    ; get crsr pos
  5301.         inc   dl
  5302.         ;
  5303.         mov   ah,2                    ; set new crsr pos
  5304.         bios_video
  5305.         pop_all
  5306.         ;
  5307.         jmp   again
  5308.  
  5309. done:
  5310.  
  5311.                                       ; display a space in white, to reset
  5312.                                       ; default colour. Should really check
  5313.                                       ; what default colour was, and save it.
  5314.  
  5315.         mov al,SPACE
  5316.         mov bl,WHITE
  5317.         mov ah,9
  5318.         mov cx,1
  5319.         bios_video
  5320.         ret
  5321. disp_str_colour        endp
  5322. ;
  5323.         if     debug                  ; Assemble only if DEBUG equate is true.
  5324. hw_blip proc                          ; Make a bleep.  This proc is hardware
  5325.                                       ; coded to aviod DOS and BIOS calls.
  5326.  
  5327.         push   ax
  5328.         push   bx
  5329.         push   cx
  5330.         push   dx
  5331.         push   di
  5332.         mov    di,2500                ; frequency in Hz
  5333.         mov    bx,15                  ; duration in 1/100 secs
  5334.         mov    al,0b6h
  5335.         out    43h,al
  5336.         mov    dx,14h
  5337.         mov    ax,4f38h
  5338.         div    di
  5339.         out    42h,al
  5340.         mov    al,ah
  5341.         out    42h,al
  5342.         in     al,61h
  5343.         mov    ah,al
  5344.         or     al,3
  5345.         out    61h,al
  5346.  
  5347. blip1:
  5348.  
  5349.         mov    cx,2801
  5350.  
  5351. spkr_on:
  5352.  
  5353.         loop   spkr_on
  5354.         dec    bx
  5355.         jnz    blip1
  5356.         mov    al,ah
  5357.         out    61h,al
  5358.         pop    di
  5359.         pop    dx
  5360.         pop    cx
  5361.         pop    bx
  5362.         pop    ax
  5363.         ret
  5364. hw_blip endp
  5365.         endif
  5366. ;
  5367.         if     debug
  5368. printregs      proc                     ; Dump the registers to LPT1.
  5369.  
  5370.         push_all
  5371.         push    ax
  5372.         push    si
  5373.         push    bp
  5374.  
  5375.         mov     si,offset axreg
  5376.         call    binasc
  5377.  
  5378.         mov     ax,bx
  5379.         mov     si,offset bxreg
  5380.         call    binasc
  5381.  
  5382.         mov     ax,cx
  5383.         mov     si,offset cxreg
  5384.         call    binasc
  5385.  
  5386.         mov     ax,dx
  5387.         mov     si,offset dxreg
  5388.         call    binasc
  5389.  
  5390.         mov     ax,ds
  5391.         mov     si,offset dsreg
  5392.         call    binasc
  5393.  
  5394.         mov     ax,es
  5395.         mov     si,offset esreg
  5396.         call    binasc
  5397.  
  5398.         mov     ax,bp
  5399.         mov     si,offset bpreg
  5400.         call    binasc
  5401.  
  5402.         mov     ax,di
  5403.         mov     si,offset direg
  5404.         call    binasc
  5405.  
  5406.         pop     bp
  5407.         pop     si
  5408.         push    si
  5409.         push    bp
  5410.         mov     ax,si
  5411.         mov     si,offset sireg
  5412.         call    binasc
  5413.  
  5414.         mov     si,offset prtstr        ;String to output
  5415.         pop     bp
  5416.         push    dx                      ;Save DX
  5417.         xor     dx,dx                   ;Printer LPT1:
  5418.  
  5419. prloop:
  5420.  
  5421.         mov     ah,0                    ;Print string
  5422.         mov     al,cs:[si]
  5423.         cmp     al,0
  5424.         je      prdone
  5425.         int     17h
  5426.         inc     si
  5427.         jmp     prloop
  5428.  
  5429. prdone:
  5430.  
  5431.         pop     dx
  5432.         pop     si
  5433.         pop     ax
  5434.         pop_all
  5435.         ret
  5436. printregs       endp
  5437.         endif
  5438. ;
  5439.         if      debug
  5440. binasc  proc    near                    ;Convert AX to ASCII and put at CS:SI
  5441.         push    ax
  5442.         mov     al,ah
  5443.         call    conval
  5444.         pop     ax
  5445.  
  5446. conval:
  5447.  
  5448.         push    ax
  5449.         push    cx
  5450.         mov     cl,4
  5451.         ror     al,cl
  5452.         pop     cx
  5453.         and     al,0Fh
  5454.         add     al,30h
  5455.         cmp     al,39h
  5456.         jbe     bin1
  5457.         add     al,7
  5458.  
  5459. bin1:
  5460.  
  5461.         mov     cs:[si],al
  5462.         inc     si
  5463.         pop     ax
  5464.         and     al,0Fh
  5465.         add     al,30h
  5466.         cmp     al,39h
  5467.         jbe     bin2
  5468.         add     al,7
  5469. bin2:
  5470.  
  5471.         mov     cs:[si],al
  5472.         inc     si
  5473.         ret
  5474. binasc  endp
  5475.         endif
  5476. ;
  5477. disk_error_msg      proc              ; display an error msg if I/O fails
  5478.         push_all
  5479.  
  5480.         mov   si,offset cs:disk_msg   ; display error message
  5481.         mov   bl,byte ptr cs:colour
  5482.         call  disp_str_colour
  5483.  
  5484.         pop_all
  5485.         ret
  5486. disk_error_msg      endp
  5487. ;
  5488. invalid_letter      proc           ; error message in reply to bad ALIAS cmd
  5489.         push_all
  5490.         mov   si,offset cs:inv_letter
  5491.         mov   bl,byte ptr cs:colour
  5492.         call  disp_str_colour
  5493.         pop_all
  5494.         ret
  5495. invalid_letter      endp
  5496. ;
  5497. syntax_error        proc 
  5498.         push_all
  5499.         mov   si,offset cs:syn_error
  5500.         mov   bl,byte ptr cs:colour
  5501.         call  disp_str_colour
  5502.         pop_all
  5503.         ret
  5504. syntax_error        endp
  5505. ;
  5506. ab_zap:                               ; de-install program
  5507.  
  5508.         call  are_you_sure            ; do we really want to zap?
  5509.         cmp   byte ptr cs:confirm,1
  5510.         je    zap_sure                ; carry on if user is sure
  5511.         jmp   bye                     ; else abandon
  5512.  
  5513. zap_sure:
  5514.  
  5515.         push_m <ax,ds,dx>
  5516.         mov   ah,25h                  ; replace old int 21h vector that was
  5517.         mov   al,21h                  ; overwritten by Alias
  5518.         mov   dx,cs:old_vec_seg
  5519.         mov   ds,dx
  5520.         mov   dx,cs:old_vec_off
  5521.         int   21h
  5522.         pop_m <dx,ds,ax>
  5523.  
  5524.         push  bp
  5525.         mov   bp,dx
  5526.         mov   byte ptr ds:[bp+1],0    ; set length to 0 to stop ALIAS Z cmd
  5527.                                       ; being executed by DOS
  5528.         mov   byte ptr ds:[bp+2],CR   ; put c/r terminator in buffer too
  5529.         pop   bp                      ; The ALIAS Z cmd can't be recalled 
  5530.                                       ; with F3, as the routine that restores
  5531.                                       ; the char bufer doesn't get called now
  5532.                                       ; that alias is no longer resident.
  5533.         ;
  5534.         push_m <es,ax,bx,cx,dx>
  5535.         mov   ah,35h                  ; int 2eh vector holds start of MCB's
  5536.         mov   al,2eh 
  5537.         int   21h                     ; int 2eh vector --> es:bx
  5538.         mov   bx,es
  5539.         dec   bx                      ; 1st MCB now at bx:0
  5540.         mov   es,bx
  5541.  
  5542. zap2:
  5543.  
  5544.         mov   es,bx
  5545.         mov   ax,word ptr es:3        ; size of block controlled by this MCB
  5546.         mov   cl,es:0                 ; marker at start of MCB
  5547.         mov   dx,word ptr es:1        ; segment that controls this block
  5548.         cmp   dx,cs:new_vec_seg       ; is block owned by alias.com?
  5549.         jne   zap1
  5550.         mov   word ptr es:1,0         ; free the block if owned by alias.com
  5551.  
  5552. zap1:
  5553.  
  5554.         cmp   cl,5ah                  ; if marker = 'Z' then no more MCB's
  5555.         je    zap3
  5556.         add   bx,ax                   ; else point to next MCB
  5557.         inc   bx
  5558.         jmp   short zap2              ; and do it all again
  5559.  
  5560. zap3:
  5561.  
  5562.         pop_m <dx,cx,bx,ax,es>
  5563.  
  5564.         push_all
  5565.         mov   bl,cs:colour            ; display de-installation message
  5566.         mov   si,offset cs:zap_msg
  5567.         call  disp_str_colour
  5568.         pop_all
  5569.  
  5570.         call  restore_flags
  5571.         iret                          ; finish. Alias now de-installed.
  5572. ;
  5573. ; -----------------------------------------------------------------------
  5574. ;                          D A T A    A R E A
  5575. ; -----------------------------------------------------------------------
  5576. ;
  5577. exec:   db 0eah                ; far jmp instruction
  5578.     old_vec_off dw 0           ; existing int 21h vector before installation
  5579.     old_vec_seg dw 0
  5580.     new_vec_off dw 0           ; new int 21h vector installed by this prog
  5581.     new_vec_seg dw 0
  5582.     command_cs  dw 0           ; the address within command.com that ...
  5583.     command_ip  dw 0           ; ... called this program
  5584.         prf_pos dw 0           ; record pos where command match starts
  5585.       prf_cflag db 0           ; used by prf_compare proc
  5586.       prf_multi db 0           ; detects multiple presses of prf_trigger key
  5587.        it_multi db 0           ; detects multiple it_key presses
  5588.         it_save dw 0           ; save cursorb for multiple F8 operations.
  5589.          prf_bx dw 0           ; used by multi prf
  5590.           csize db 1           ; 1 = small, 2 = big cursor size
  5591.     def_fn_msg  db 'Default data file is ',EOM
  5592.     defdir_hdr  db 'Z:\'       ; Def_dir header.Drive letter to be filled in.
  5593.     def_dir     db 66 dup(0)   ; Note the dir where ALIAS.DAT was loaded from.
  5594.     default_fn  db 'ALIAS.DAT',0  ; default filename
  5595.     match       db 'alias '           ; command looked for
  5596.    match_u_case db 'ALIAS '           ; check upper case too
  5597.       count_msg db CR,LF,'Aliases defined: '  ; used by ALIAS I.
  5598.      count_msg1 db '00/'                      ; 00's filled by count_aliases
  5599.      count_msg2 db '00',CR,LF,EOM
  5600.     buffer      db LHS_LEN dup(0)   ; temporary store for user's string
  5601.     buffer2     db LHS_LEN dup(0)   ; used by D and L commands for searching
  5602.     param_buff  db 129 dup(0)       ; save chars to be re-added after aliasing
  5603.     nest_flag   db 0                ; gets set if an expansion takes place
  5604.     match_pos   dw 0                ; offset into ab_table where match starts
  5605.     match_len   db 0                ; length of match string
  5606.     arg_end     db 0
  5607.     str_end     db 0
  5608.     spare       dw 0           ; position of spare entry in table
  5609.     temp1       dw 0           ; temporary storage to avoid using stack
  5610.     temp2       dw 0
  5611.     temp3       dw 0
  5612.    sort_counter db 0           ; used by sorting routine
  5613.    sort_pointer dw 0           ; ditto
  5614.     swap_flag   db 0           ; ditto
  5615.    sort_entries db 0           ; ditto
  5616.     confirm     db 0           ; set/cleared by are_you_sure proc
  5617.     sure_msg    db CR,LF,'Are you sure? (Y/N) ',EOM
  5618.     press_msg   db '>> Press any key to continue <<',EOM
  5619.     kb_str_len  db 0           ; save length of string got by func 0Ah
  5620.     kb_str_ch1  db 0           ; save 1st char of str before setting to cr
  5621.     do_kb_str   db 0           ; do we want to put back str? 0 = no
  5622.     echo_temp   db 0           ; used by echo proc
  5623.     echo_flag   db 0           ; used by echo and disp_str_colour procs
  5624.     list_temp   db 0           ; used by list proc
  5625.     list_temp2  dw 0           ; used by list proc
  5626.     list_count  db 0           ; counter so LIST can pause when screen full
  5627.       page_len  db 0           ; used in LIST proc
  5628.     old_col     db 0           ; save current colour during ALIAS C command
  5629.     zap_msg     db CR,LF,'ALIAS de-installed.',CR,LF,EOM
  5630.     multi_line_outstanding db 0  ; is part of multi-line remaining?  0 = no
  5631.     multi_start dw 0
  5632.     multi_len   db 0
  5633.     save_flags  dw 0             ; save the flags register here
  5634.     error_msg   db CR,LF,'Error - type ALIAS ? for help.',CR,LF,EOM
  5635.     err_nfound  db CR,LF,'No such alias.',EOM
  5636.     exist_msg   db CR,LF,'Specified alias already exists.',CR,LF,EOM
  5637.     inv_letter  db CR,LF,'Invalid command.  Type ALIAS ? for help.',CR,LF,EOM
  5638.     syn_error   db CR,LF,'Syntax error.  Type ALIAS ? for help.',EOM
  5639.     disk_msg    db CR,LF,'Disk error. Possibly File Not Found,'
  5640.                 db ' or Disk Full.',CR,LF,EOM
  5641.      no_fit_msg db CR,LF,'Error - string too long.',CR,LF,EOM
  5642.       star_flag db 0
  5643.     table_full_msg db CR,LF,'No more space in Alias table.',CR,LF,EOM
  5644.     left_sq_br  db '[',0         ; for use if show mode is on
  5645.     rght_sq_br  db ']',0
  5646.     command_letter db 0          ; single-char ALIAS command store
  5647.     version     db CR,LF
  5648.                 db 'ALIAS v',VERS,CR,LF
  5649. ife online_help
  5650.                 db '(Short version)',CR,LF
  5651. endif
  5652.                 db EOM
  5653.     colour_msg  db CR,'Press SPACE to see colours, RETURN to select'
  5654.                 db ' or ESC to quit.',EOM
  5655.     msg_show    db 'Expanded aliases will echo on screen.',CR,LF,EOM
  5656.     msg_hide    db 'Expanded aliases will not echo.',CR,LF,EOM
  5657.     msg_off     db 'Aliases are turned off.',CR,LF,EOM
  5658.     msg_prompt  db 'Aliases from DOS prompt only.',CR,LF,EOM
  5659.     msg_global  db 'Global expansion set.',CR,LF,EOM
  5660.  
  5661. if debug            ; This data used by printregs proc
  5662.  
  5663.         prtstr  db 'AX-'
  5664.          axreg  db '----'
  5665.                 db ' BX-'
  5666.          bxreg  db '----'
  5667.                 db ' CX-'
  5668.          cxreg  db '----'
  5669.                 db ' DX-'
  5670.          dxreg  db '----'
  5671.                 db ' DS-'
  5672.          dsreg  db '----'
  5673.                 db ' ES-'
  5674.          esreg  db '----'
  5675.                 db ' BP-'
  5676.          bpreg  db '----'
  5677.                 db ' DI-'
  5678.          direg  db '----' 
  5679.                 db ' SI-'
  5680.          sireg  db '----'
  5681.                 db CR,LF,0
  5682. endif
  5683.  
  5684. if online_help                          ; Only assemble online help if EQUate
  5685.                                         ; set.  Omitting help saves memory.
  5686.  
  5687. help_text db LF,CR
  5688. db '╔═══════╤═════════════════════════════════════════════════════════╤════════════╗',CR,LF
  5689. db '║ v',VERS,' │   ALIAS Help Screen (Read ALIAS.HLP for more details)   │  (c)RJS ''89║',CR,LF
  5690. db '╟───────┴─────────────────────────────────────────────────────────┴────────────╢',CR,LF
  5691. db '║ Make DA an alias for DIR A:                ALIAS A DA DIR A:                 ║',CR,LF
  5692. db '║ Delete alias DA                            ALIAS D DA                        ║',CR,LF
  5693. db '║ List aliases                               ALIAS L aliasname                 ║',CR,LF
  5694. db '║ Read aliases from file (default ALIAS.DAT) ALIAS R filename                  ║',CR,LF
  5695. db '║ Write aliases to file  (default ALIAS.DAT) ALIAS W filename                  ║',CR,LF
  5696. db '╟────────────────────────────────────────────────────┬─────────────────────────╢',CR,LF
  5697. db '║ Flush all aliases from memory              ALIAS F │Recall commands        ',24,' ║',CR,LF
  5698. db '║ Aliases valid from prompt only (default)   ALIAS P │Separator              & ║',CR,LF
  5699. db '║ Aliases valid globally                     ALIAS G │Override alias         ~ ║',CR,LF
  5700. db '║ Aliases not valid (turn them off)          ALIAS N │Beg/End of cmnds  PgUp/Dn║',CR,LF
  5701. db '║ Show aliases on screen before expanding    ALIAS S │Quit circular alias   ESC║',CR,LF
  5702. db '║ Hide aliases (don''t show them)             ALIAS H ├─────────────────────────╢',CR,LF
  5703. db '║ Display status and setup info              ALIAS I │WordRt/Lt   Ctrl ',26,'/Ctrl ',27,'║',CR,LF
  5704. db '║ Change colour used by ALIAS program        ALIAS C │BegLn/EndLn      Home/End║',CR,LF
  5705. db '║ De-install ALIAS                           ALIAS Z │DelWrdL/R    Ctrl-W/Alt-W║',CR,LF
  5706. db '║ Display this help screen                   ALIAS ? │DBOL/DEOL    Ctrl-L/Alt-L║',CR,LF
  5707. db '║ List contents of command recall buffer     ALIAS B │Undelete           Ctrl-U║',CR,LF
  5708. db '╟1─────┬2──────┬3───────┬4──────┬5──────┬6──────┬7───┴──┬8───────┬9─────┬10────╢',CR,LF
  5709. db '║      │       │        │       │       │       │       │Complete│  It  │ Also ║',CR,LF
  5710. db '╚══════╧═══════╧════════╧═══════╧═══════╧═══════╧═══════╧════════╧══════╧══════╝',CR,LF
  5711. db EOM
  5712.  
  5713. else                                ; If no online help required, inform user.
  5714.  
  5715. help_text db LF,CR,' No online help available in short',CR,LF
  5716.           db ' version. Read ALIAS.HLP file for help.',CR,LF,EOM
  5717. endif
  5718.  
  5719.                                  ; These 5 bytes get saved at the top of the
  5720.                                  ; data file.
  5721. table_top:
  5722.  
  5723.        ins_mode db 0             ; 0 = overwrite mode, 1 = insert mode
  5724.  
  5725.     ab_status   db 1             ; alias status. 1 = on, 0  = off. This too 
  5726.                                  ; is saved with table.
  5727.     expand_from db 0             ; 0 = dos prompt (default), 1 = global. This
  5728.                                  ; gets saved with table-don't move this db.
  5729.     colour      db 7             ; default colour. changed with C command,
  5730.                                  ; and gets saved with table. 7 = white.
  5731.     echo_status db 0             ; 0 = hide (default), 1 = show. also gets
  5732.                                  ; saved with table.
  5733.  
  5734.      ab_table db ((RHS_LEN+LHS_LEN+1)*TBL_LEN) dup(0)  ; the alias table
  5735.    table_end  db 0F0h                                  ; used by count_aliases
  5736.  
  5737.                                   ;Data Area for Dos Editor
  5738.  
  5739.                                   ;Table of keys and their commands' address
  5740.  
  5741. cmndtbl:
  5742.  
  5743.    dw   ltarrw,   curslf          ;move cursor left one column
  5744.    dw   rtarrw,   cursrt          ;move cursor right one column
  5745.    dw   cntlf,    wordl           ;move cursor left word
  5746.    dw   cntrt,    wordr           ;move cursor right word
  5747.    dw   homekey,  begline         ;move cursor to beginning of line
  5748.    dw   endkey,   endline         ;move cursor to end of line
  5749.    dw   uparrw,   cursup          ;move cursor up one line
  5750.    dw   dnarrw,   cursdn          ;move cursor down one line
  5751.    dw   f3key,    f3proc          ;non-destructive f3
  5752.    dw   bs,       delchrl         ;delete char left of cursor
  5753.    dw   delkey,   delchrr         ;delete char right of cursor
  5754.    dw   'W'-cntl, delwrdl         ;delete word left of cursor
  5755.    dw   altw,     delwrdr         ;delete word right of cursor
  5756.    dw   'L'-cntl, dellinl         ;delete to beginning of line
  5757.    dw   altl,     dellinr         ;delete to end of line
  5758.    dw   altk,     delline         ;delete all characters on line
  5759.    dw   escape,   escproc         ;delete all characters on line
  5760.    dw   'U'-cntl, undelet         ;undelete text from buffer
  5761.    dw   altu,     undelet         ;undelete text from buffer
  5762.    dw   insert,   inskey          ;toggle insert/overwrite mode
  5763.    dw prf_trigger,do_prf          ;enter prf routine if trigger key pressed
  5764.    dw     it_key ,it_proc         ;F8 key
  5765.    dw    also_key,also_proc       ;F10 key
  5766.    dw     pgdnkey,pg_dn_proc      ;PgDn key
  5767.    dw     pgupkey,pg_up_proc      ;PgUp Key
  5768.    dw       f1key,f1proc          ; F1 key does nothing
  5769.    dw   0000h,    nomatch         ;no match, place the char in buffer
  5770.  
  5771. bublbeg     db    maxlin dup (?)  ;beginning of bubble buffer
  5772. Bublend     db    ?               ;end of bubble buffer
  5773. Cursorb     dw    ?               ;pointer to beginning of cursor
  5774. Cursore     dw    ?               ;pointer to end cursor in text buffer
  5775. Unleft      dw    ?               ;undelete data counter on the left
  5776. Unright     dw    ?               ;undelete data counter on the right
  5777. Scrnwdt     dw    ?               ;screen width in columns
  5778. Disppag     db    ?               ;display page
  5779. Maxchar     dw    ?               ;max number of char in line
  5780. dcbuffer    db    maxlin+2 dup(?) ; Buffer for DOS compatibility
  5781. dcbufend    db    ?               ; Mark end of dcbuffer
  5782. dcpointer   dw    ?               ; pointer into dcbuffer
  5783.  
  5784.                                   ;Screen relative variables
  5785.  
  5786. Leftx       dw    ?               ;X position of the left most character
  5787. edcursx     dw    ?               ;X position of the editor cursor
  5788. cursorx     dw    ?               ;X position of the cursor
  5789. cursory     db    ?               ;Y position of the cursor
  5790.  
  5791.                                   ;Display line relative variables
  5792.  
  5793. linelen     dw    ?               ;length of display line
  5794. Updatex     dw    ?               ;X position for character update
  5795.  
  5796.                                   ;Text line relative variables
  5797.  
  5798. startx      dw    ?               ;column # of start of the display line
  5799. scrnimg     db    maxswdt dup (?) ;image of screen display line
  5800.  
  5801. dosvect     dd    ?               ;contains pointer to Dos vector
  5802. oldsp       dd    ?               ;contains old stack pointer
  5803. codeseg     dw    ?               ;code segment for this program
  5804.  
  5805.                                   ;Storage for the command recording functions
  5806.  
  5807. cmdtop     db     cmdlen-1 dup (?);ring buffer for line entries
  5808. cmdbot     db     ?               ;end of ring buffer
  5809. cmdold     dw     ?               ;pointer to oldest command
  5810. cmdnew     dw     ?               ;pointer to newest command
  5811. cmdpnt     dw     ?               ;pointer to current command
  5812.  
  5813.  
  5814. stckbot    db     200 dup (?)     ;storage for the stack
  5815. stcktop    db     ?               ;top of the stack
  5816.                                   ;End of editor data
  5817.  
  5818. ; -----------------------------------------------------------------------
  5819. ;                   NOTHING BELOW HERE GETS MADE RESIDENT
  5820. ; -----------------------------------------------------------------------
  5821.  
  5822. init:   push  cs                      ; set ds = cs
  5823.         pop   ds
  5824.         jmp   install
  5825.  
  5826.     greet db 'ALIAS v',VERS,' now installed.'
  5827.  
  5828. ife online_help
  5829.           db CR,LF,'(Short version.  No online help).'
  5830. endif
  5831.  
  5832.    db CR,LF,'(c)Robert Schifreen 1989.'
  5833.    db CR,LF
  5834.    db CR,LF,'ALIAS gives you:'
  5835.    db CR,LF,' - Aliasing for MS-DOS commands'
  5836.    db CR,LF,' - Recall of previous commands'
  5837.    db CR,LF,' - Full editing of recalled commands'
  5838.    db CR,LF,' - Automatic command completion.'
  5839.    db CR,LF,'For help, use the ALIAS ? command.',CR,LF
  5840.  
  5841.    db CR,LF,'IMPORTANT:  ALIAS is not "free software" and it is not "public domain".'
  5842.    db CR,LF,'You may use the software for one month, and you are welcome to give'
  5843.    db CR,LF,'copies to anyone you wish.  If, after the one month trial period, you'
  5844.    db CR,LF,'intend to continue using the program, you or your company must register it'
  5845.    db CR,LF,'by sending a contribution of up to £25 or 30 US dollars to the author at'
  5846.    db CR,LF,'65 Latchingdon Court, 26 Forest Road, London, E17 6JT, England.',CR,LF
  5847.  
  5848.    db CR,LF,'Registered users receive: extra documentation; news of major upgrades;'
  5849.    db CR,LF,'a special memory-saving version; dial-up technical support in the UK'
  5850.    db CR,LF,'and the US on the Cix and Bix networks; full MASM source code (¼MB) for'
  5851.    db CR,LF,'the latest version of ALIAS (please state disk size when registering).'
  5852.    db CR,LF,'$'
  5853.  
  5854. wrong_dos db 'ALIAS runs only under DOS version 2, 3 or 4.',CR,LF,DOS_EOM
  5855. alrdy_in  db 'There seems to be a copy of ALIAS already in memory.',CR,LF
  5856.           db 'Type ALIAS ? for help.',CR,LF,EOM
  5857. default   db 'Loading ALIAS.DAT...',CR,LF,DOS_EOM
  5858.  
  5859. install:
  5860.  
  5861.                                       ; With ALIAS installed, calling DOS
  5862.                                       ; function 35h increments 0040:00F4h
  5863.                                       ; to show that ALIAS is resident. Use
  5864.                                       ; this check to see if prog is
  5865.                                       ; already installed.
  5866.  
  5867.  
  5868.         push_m <ax,bx,cx,ds,dx,es>
  5869.         mov   ax,40h
  5870.         mov   ds,ax                   ; segment for ICA
  5871.         mov   ch,byte ptr ds:0f4h     ; get current value of ICA byte
  5872.         mov   ah,35h                  ; now call function 35h
  5873.         mov   al,5                    ; get value of int 5, though exact value
  5874.                                       ; doesn't really matter.
  5875.         int   21h                     ; gets int 5 vector into es:bx
  5876.         mov   ax,40h                  ; point to ica again
  5877.         mov   ds,ax
  5878.         mov   cl,byte ptr ds:0f4h     ; get ICA byte again.
  5879.         inc   ch
  5880.         cmp   ch,cl                   ; Is cl = ch + 1?     
  5881.         pop_m <es,dx,ds,cx,bx,ax>
  5882.         jne carry_on_installing       ; If cl becomes ch+1, then increment
  5883.                                       ; took place so ALIAS is resident.
  5884.  
  5885.                                        ; ALIAS is already loaded so don't
  5886.                                        ; load it again.
  5887.         push_all
  5888.         mov   si,offset cs:alrdy_in
  5889.         mov   bl,cs:colour
  5890.         call  disp_str_colour          ; display message
  5891.         pop_all
  5892.         int   20h                     ; terminate execution of ALIAS.COM
  5893.  
  5894. carry_on_installing:
  5895.  
  5896.         push_m <ax,dx,ds>
  5897.         mov   ah,30h                  ; get DOS version number
  5898.         int   21h
  5899.         cmp   al,2
  5900.         pop_m <ds,dx,ax>
  5901.         je    dos_ok                  ; continue if 2
  5902.  
  5903.         push_m <ax,dx,ds>
  5904.         mov   ah,30h                  ; get it again
  5905.         int   21h
  5906.         cmp   al,3
  5907.         pop_m <ds,dx,ax>
  5908.         je    dos_ok                  ; continue if it's a 3
  5909.  
  5910.  
  5911.         push_m <ax,dx,ds>
  5912.         mov   ah,30h                  ; get it again
  5913.         int   21h
  5914.         cmp   al,4
  5915.         pop_m <ds,dx,ax>
  5916.         je    dos_ok                  ; continue if it's a 4
  5917.  
  5918.  
  5919.         push_m <ax,dx,ds>
  5920.         mov   ah,30h                  ; get it again
  5921.         int   21h
  5922.         cmp   al,0Ah
  5923.         pop_m <ds,dx,ax>
  5924.         je    dos_ok                  ; continue if 10, ie DOS box of OS/2
  5925.  
  5926.         mov   ah,9                    ; display error msg if DOS is not 2 or 3
  5927.         mov   dx,offset wrong_dos
  5928.         push  ds
  5929.         push  cs
  5930.         pop   ds
  5931.         int   21h
  5932.         pop   ds
  5933.         ret                           ; and terminate
  5934.  
  5935. dos_ok:
  5936.  
  5937.         mov   ah,35h                  ; get interrupt vector
  5938.         mov   al,21h                  ; number 21h - dos function call
  5939.         int   021h
  5940.         mov   ax,es
  5941.         mov   cs:old_vec_seg,ax
  5942.         mov   cs:old_vec_off,bx
  5943. ;
  5944.         mov   ah,25h                  ; set interrupt vector
  5945.         mov   al,21h                  ; specify vector to be set
  5946.         mov   dx,offset intent
  5947.         int   21h
  5948.         mov   ah,35h                  ; find out new interrupt vector
  5949.         mov   al,21h                  ; for int 21h 
  5950.         int   21h
  5951.         mov   ax,es
  5952.         mov   cs:new_vec_seg,ax
  5953.         mov   cs:new_vec_off,bx
  5954. ;
  5955.                                       ; If alias.dat exists, load it
  5956.         push_m <ax,bx,cx,dx,ds>
  5957.         push  cs                      ; point to filename
  5958.         pop   ds
  5959.         mov   dx,offset cs:default_fn
  5960.         mov   ah,3dh                  ; open file
  5961.         mov   al,0                    ; for reading
  5962.         int   21h
  5963.         jc    no_default_file         ; quit if file not found 
  5964. ;
  5965.                                       ; print msg to say we're loading file
  5966.         push_all
  5967.         mov   ah,9
  5968.         mov   dx,offset cs:default
  5969.         push  cs
  5970.         pop   ds
  5971.         int   21h
  5972.         pop_all
  5973. ;
  5974.         mov   bx,ax                   ; put handle in correct place
  5975.         mov   cx,((RHS_LEN + LHS_LEN + 1) * TBL_LEN) + 5 ; table plus signat
  5976.         push  cs
  5977.         pop   ds
  5978.         mov   dx,offset cs:table_top  ; start of data area
  5979.         mov   ah,3fh
  5980.         int   21h
  5981.         ;
  5982.         mov   ah,3eh                  ; close file
  5983.         int   21h
  5984. ;
  5985.                                       ; Get the name of the current directory,
  5986.                                       ; ie the one that ALIAS.DAT is in.
  5987.                                       ; Use this directory for future writes
  5988.                                       ; if an ALIAS W command is used without
  5989.                                       ; a specified filename.
  5990.         push_m <ax,ds,dx,si>
  5991.         mov   ah,47h
  5992.         mov   dl,0                    ; default drive
  5993.         push  cs
  5994.         pop   ds
  5995.         mov   si,offset cs:def_dir    ; buffer for the directory
  5996.         int   21h
  5997.         pop_m <si,dx,ds,ax>
  5998. ;
  5999.                                       ; Func 47h doesn't return the drive
  6000.                                       ; letter, so get it and plug it in.
  6001.         push  ax
  6002.         mov   ah,19h
  6003.         int   21h                     ; get zero-based drive code into al.
  6004.         add   al,'A'                  ; convert to a letter
  6005.         mov   byte ptr cs:defdir_hdr,al   ; and put it at front of string
  6006.         pop   ax
  6007. ;
  6008.                                       ; Now find the end of the path string,
  6009.                                       ; and put a backslash and filename on,
  6010.                                       ; to create a full path and file name.
  6011.  
  6012.         push_all
  6013.         push  cs
  6014.         pop   es                      ; scasb needs string at es:di
  6015.         cld                           ; clear direction flag
  6016.         mov   al,0                    ; char to search for
  6017.         mov   cx,66                   ; length of string to search
  6018.         mov   di,offset cs:def_dir    ; addr of string to search
  6019.         repne scasb                   ; search till we find a 0.  We will
  6020.                                       ; definitely find one eventually!
  6021.         dec   di                      ; di now has adr of the zero byte
  6022.  
  6023.         cmp   byte ptr cs:[di-1],'\'  ; Are we in root?
  6024.         je    in_root                 ; Yes, then backslash is already there
  6025.  
  6026.         mov   byte ptr cs:[di],'\'    ; else put backslash on end of string
  6027.  
  6028.                                       ; Now copy the default filename from
  6029.                                       ; default_fn to the end of the path.
  6030.  
  6031.         inc   di                      ; point to char after trailing backslash
  6032.  
  6033. in_root:
  6034.  
  6035.         mov   si,offset cs:default_fn ; point to start of default filename
  6036.  
  6037. copy1:
  6038.  
  6039.         lodsb                         ; get a byte from the filename into al
  6040.         cmp   al,0                    ; done?
  6041.         je    copy_done
  6042.         mov   byte ptr cs:[di],al     ; put the byte into place
  6043.         inc   di                      ; SI got incremented by the lodsb.
  6044.         jmp   short copy1             ; and go get the next byte
  6045.  
  6046. copy_done:
  6047.  
  6048.         pop_all
  6049.  
  6050. no_default_file:                      ; default file was not in current dir
  6051.                                       ; so don't load it.
  6052.  
  6053.         pop_m <ds,dx,cx,bx,ax>
  6054.  
  6055.         show   greet                  ; Display welcome message.  Note that
  6056.                                       ; we use the standard DOS call to display
  6057.                                       ; this message, rather than the fancy
  6058.                                       ; colour string printer that is used
  6059.                                       ; everywhere else in ALIAS.  This is so
  6060.                                       ; that the user can redirect the greet
  6061.                                       ; message to NUL if he wishes.
  6062.  
  6063.  
  6064.                                       ; Set up the command line editor
  6065.  
  6066.         mov    sp,offset stcktop      ;set stack pointer to top of stack
  6067.         mov    cs:codeseg,cs          ;save this code segment
  6068.         mov    ds,cs:codeseg          ;DS is same as code segment
  6069.         call   inittny                ;initialize the editor
  6070.  
  6071.  
  6072.                                       ; Free the environment block allocated
  6073.                                       ; to us, as we don't need it.  The adr
  6074.                                       ; of the block is in PSP:2ch.
  6075.  
  6076.                                       ; If the debug flag is set, do not
  6077.                                       ; assemble this routine.  With the
  6078.                                       ; environment intact, one can use SMAP
  6079.                                       ; to find the name of the loaded version
  6080.                                       ; of the program, which helps me to
  6081.                                       ; remember whether ALIAS.COM is loaded,
  6082.                                       ; or whether it's a temporary version of
  6083.                                       ; the file, used for test purposes.
  6084.  
  6085.         ife    debug
  6086.         push_m <ax,es>
  6087.         mov    es,cs:[2ch]            ; get seg adr of our environment block
  6088.         mov    ah,49h                 ; free a block
  6089.         int    21h                    ; free the block
  6090.         pop_m <es,ax>                 ; all done
  6091.         endif
  6092.  
  6093.         mov   ax,3100h                ; terminate and remain resident
  6094.         mov   dx,rsize                ; size of residency in paragraphs
  6095.         int   21h                     ; done
  6096.  
  6097.         code  ends
  6098.         end   start                   ; start execution at routine 'start'
  6099.  
  6100. ; -----------------------------------------------------------------------
  6101. ;                       (c) Robert Schifreen 1985,1989
  6102. ; -----------------------------------------------------------------------
  6103.